3

I am using ajax to submit log in and log out credentials. The log in and log out forms are replaced with html returned by a successful response. No page loading is happening page content is loaded via an ajax get request upon successful log in or log out.

I can successfully log in and then log out, but when I attempt to log in a second time I am receiving a nonce failure (-1) from check_admin_referer(). I have verified the nonce being sent during the second log in is different then the first submission, but that as far as I understand with nonce. This nonce is sent back to the ajax request during the log out process.

Have I over looked the need for something to be refreshed or stored somewhere in a session or global variable? My code works during the first attempt for logging in and logging out sharing my code is not likely beneficial here.

Does anyone have any idea why the nonce I receive is invalid?

EDITS BELOW

Please see my code, it's a mix of php and javascript

<?php
/* the php sidebar menu for a logged in user
 * this is also fetched by the ajax log in action
 */
function not_logged_in_menu() { ?>

    <div class="login-form">
        <h2>Login</h2>

        <form method="post" action="<?php site_url(); ?>/wp-login.php" class="wp-user-form">
            <div class="input-login">
                <div class="loader"></div>
                <input type="submit" class="login ui-btn" name="Login" value="Login" />
                <span class="gzp-icon-login"></span>
            </div>
            <div class="input-prepend">
                <span class="add-on icon-username"></span>
                <input type="text" name="log" value="" class="input-medium" id="user_login" placeholder="Username" />
            </div>
            <?php /*<br class="clearer" />*/ ?>
            <div class="input-prepend">
                <span class="add-on icon-password"></span>
                <input type="password" name="pwd" value="" id="user_pass" class="input-medium" placeholder="Password" />
            </div>
            <?php wp_nonce_field( 'ajax-login-nonce', 'security' ); ?>                  
        </form>
    </div> <?php
}

/* the php sidebar menu for a logged out user
 * this is also fetched by the ajax log out action
 */
function logged_in_menu() {
        global $user_identity; ?>

    <div class="login-form">
        <h2 class="welcome">Welcome<br /><?php echo $user_identity; ?></h2>

        <a href="<?php echo wp_logout_url( home_url() ); ?>" id="logout" class="btn btn-inverse" title="Logout">Logout</a>
        <div class="loader"></div>
        <div class="clearer"></div>
    </div> <?php
}

/* the php login ajax action */
function ajax_login(){

        check_ajax_referer( 'ajax-login-nonce', 'security' ); // on the second log in attempt with no page refresh this
                                                              // function fails her

        // Nonce is checked, get the POST data and sign user on
        $info = array();
        $info['user_login'] = $_POST['username'];
        $info['user_password'] = $_POST['password'];
        $info['remember'] = true;

        $user = wp_signon( $info, false );

        if ( is_wp_error($user) ){
                echo json_encode(array('loggedin'=>false, 'message'=>__('Wrong username or password.')));
                die();
        }

        //setting the user variables so the globals have content without an actual page load
        wp_set_current_user( $user->ID, $user->user_login );
        wp_set_auth_cookie( $user->ID, true, false );
        do_action( 'wp_login', $user->user_login );

        ob_start();
        gzp_logged_in_menu();
        $menu_content = ob_get_contents();
        ob_end_clean();

        echo json_encode(array('loggedin'=>true, 'message'=>__('Login successful, redirecting...'), 'menu_content'=>$menu_content,'user_signon'=>$user));

        die();
}
add_action( 'wp_ajax_nopriv_ajaxlogin', 'ajax_login' );


/* the php log out ajax action */
function ajax_logout(){

        // First check the nonce, if it fails the function will break
        wp_verify_nonce( $_POST['security'], 'log-out' );

        wp_logout();

        ob_start();
        gzp_not_logged_in_menu();
        $menu_content = ob_get_contents();
        ob_end_clean();

        echo json_encode(array('loggedout'=>true, 'message'=>__('Logout successful, redirecting...'), 'menu_content'=>$menu_content));

        die();
}
add_action( 'wp_ajax_ajaxlogout', 'ajax_logout' );
?>


<script type="text/javascript">
/* javascripted loaded in the head of page on page load */
jQuery(document).ready(function(event) {
        admin_bar_login();
        admin_bar_logout();
});    
/* the ajax post for a log in attempt */
function admin_bar_login() {
        /* login action */
        jQuery('form.wp-user-form').on('submit', function(e) {
                e.preventDefault();

                jQuery('.login-form input.login').parent('.input-login').addClass('loading').show();
                console.log(jQuery('form.wp-user-form #security').val());
                jQuery.ajax({
                        type: 'POST',
                        dataType: 'json',
                        url: ajaxurl,
                        data: {
                                'action': 'ajaxlogin', //calls wp_ajax_nopriv_ajaxlogin
                                'username': jQuery('form.wp-user-form #user_login').val(),
                                'password': jQuery('form.wp-user-form #user_pass').val(),
                                'security': jQuery('form.wp-user-form #security').val()
                        },
                        success: function(data){
                                if (data.loggedin == true){
                                        jQuery('.navigation-right .menu').html(data.menu_content);
                                        AAPL_loadPage(document.location.toString(),1); //refresh the #content of the page
                                        admin_bar_logout(); //this adds the event handler to the log out content just added
                                        jQuery.bootstrapGrowl(data.message);
                                }
                                else if(data.loggedin == false) {
                                        jQuery('.login-form input.login').parent('.input-login').removeClass('loading');
                                        jQuery.bootstrapGrowl(data.message);
                                }
                        },
                        fail: function(data){
                                if(data.loggedin == 'false')
                                        jQuery.bootstrapGrowl(data.message);
                        }
                });                                            
        });
}
/* the ajax post for a log out attempt */
function admin_bar_logout() {
        //logout action
        jQuery('#logout').on('click', function(e) {
                e.preventDefault();

                jQuery(this).parent('.login-form').addClass('loading').show();
                var href = jQuery(this).attr('href'),
                    vars = href.split("&"),
                    wp_nonce = '_wpnonce',
                    security = '';

                for (var i=0;i<vars.length;i++) {
                           var pair = vars[i].split("=");
                           if(pair[0] == wp_nonce){security = pair[1];}
                }

                jQuery.ajax({
                        type: 'POST',
                        dataType: 'json',
                        url: ajaxurl,
                        data: {
                                'action': 'ajaxlogout', //calls wp_ajax_ajaxlogout
                                'security': security,
                        },
                        success: function(data){
                                if (data.loggedout == true){
                                        jQuery('.navigation-right .menu').html(data.menu_content);
                                        AAPL_loadPage(document.location.toString(),1); //refresh the #content of the page
                                        admin_bar_login(); //this adds the event handler to the log in content just added
                                        jQuery.bootstrapGrowl(data.message);
                                }
                                else if(data.loggedin == false) {
                                        jQuery('.login-form input.login').parent('.input-login').removeClass('loading');
                                        jQuery.bootstrapGrowl(data.message);
                                }
                        },
                        fail: function(data){
                                if(data.loggedin == 'false')
                                        jQuery.bootstrapGrowl(data.message);
                        }
                });                                            
        });
}
</script>

Solution Below

The correct answer for my issue was marked below, but I also had another issue with my user not actually being logged out. The nonce being returned was a logged in nonce. When I tried to log back in as an anonymous user the nonce was invalid to wp_verify_nonce().

I have found that simply using wp_logout() to log out wasnt enough in my case. The $current_user variable still retained all of the user data and is_user_logged_in() returned true. It wasnt until I set wp_set_current_user(0) did I see the user was actually logged out.

I have also removed the need for a nonce during log in.

See this post for discussion on that topic

wp_logout Not Logging Me Out

4
  • 4
    It might make sense to show some of your code, preferably distilled to simple example others can try to reproduce.
    – Rarst
    Dec 5, 2014 at 20:59
  • I have updated my post with a link to my code. I have just finished reading a couple of articles which state the nonce for any action within a 24 hour period should be the same. I am noticing the nonce is different on the form added to the page from the ajax call. Could this be where my issue is?
    – stoi2m1
    Dec 6, 2014 at 7:47
  • OK That is exactly what is going on. The nonce is X on first log in. After I log out the nonce in now Y. If I reload the page and the nonce goes back to X. Maybe Im not completely logging out or maybe some global or session variable is not being destroyed or updated. Any ideas?
    – stoi2m1
    Dec 6, 2014 at 7:56
  • You should add your code directly to your question. Do not use third party services to host your code. Thank you Dec 6, 2014 at 9:24

2 Answers 2

1

I hadn't run your code, but my educated guess is that the fault in your code flow is that nonces are user specific. While anonymous nonce is possible, it is useless for its purpose because it would be same for all anonymous users.

So there is likely mismatch somewhere and you are trying to use nonce of specific user, while being anonymous.

1
  • I see, and I have verified that the default log in form found on the wp-login.php page does not have a nonce field. Also the wp_login_form() function does not add a nonce field to the form either. I think I was working from an example I found some where showing how to log in with ajax which added the field to the form. I will be removing the field. Thanks for your input.
    – stoi2m1
    Dec 6, 2014 at 13:55
0

Another thing to consider is that wp nonce system uses both the current user id, and the sessiontoken (wordpress_logged_in_... cookie).

If you look at wp_verify_nonce function source you'll see it compares the nonce with hash of ( current and last 12-hr period + '|' + action + '|' + currentuser-id + '|' + sessiontoken )

Any change of any of those variables would make the hash not match.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.