Identical wp_rest nonce returned from rest_api

Question

TLDR: How can I force a new nonce to be returned, so that AJAX works without refreshing the page?

Following on from Nonces and Ajax request to REST API and verification I implemented the Nonce functionality, with callback permissions and the ‘intent’ of my routes are now secure.

I enqueue Axios, with wp_rest nonce as a local script setting.

    // Register custom variables for the AJAX script.
    wp_localize_script( 'axios', 'axiosScriptVars', [
        'root'  => esc_url_raw( rest_url() ),
        'nonce' => wp_create_nonce( 'wp_rest' ),
    ]);

I set my Ajax headers up with axiosScriptVars.nonce. I POST – this works. I return a NONCE from my REST_API endpoint’s response, and update my Ajax header ready for the next POST…

Example of my log in and log out route:

function ajax_logout() {
    try {
    wp_logout();
    $nonce = wp_create_nonce( 'wp_rest' );
    return array('loggedin'=>false, 'message'=>__('Logged out successfully'), 'name'=>false, 'email'=>false, 'nonce'=>$nonce );
    } catch (Exception $e) {
        echo 'Caught exception: ',  $e->getMessage(), "n";
        die;
    }
}


function ajax_login(){
    $_POST = json_decode(file_get_contents("php://input"),true);

    $info = array();
    $info['user_login'] = !empty($_POST['username']) ? sanitize_text_field( $_POST['username'] ) : null;
    $info['user_password'] = !empty( $_POST['password'] ) ? sanitize_text_field( $_POST['password'] ) : null;
    $info['remember'] = true;
    
    $user = wp_signon( $info, true );
    $nonce = wp_create_nonce( 'wp_rest' );

    if ( is_wp_error($user) ){
        return array('loggedin'=>false, 'message'=>__('Wrong username or password.'), 'name'=>false, 'email'=>false, 'nonce'=>$nonce );
    } else {
        return array('loggedin'=>true, 'message'=>__('Login successful'), 'name'=>$user->data->display_name, 'email'=>$user->data->user_email, 'nonce'=>$nonce );
    }
}


add_action( 'rest_api_init', function () {
    register_rest_route( 'rw-user/v1', '/log-in', array(
        'methods' => 'POST',
        'callback' => 'ajax_login',
        'permission_callback' => '__return_true'
    ));
    register_rest_route('rw-user/v1','/log-out', array(
        'methods' => 'POST',
        "callback" => 'ajax_logout',
        "permission_callback" => function () {
            return current_user_can( 'administrator' );
        }
    ));
});

POSTING fails because the New NONCE is identical to the old.

So I thought WordPress must return a new nonce in the response header… I check and see the "x-wp-nonce" header – only it is also identical!

(I read something about not using wp_json_success in REST routes – as the rest api already turns the return of your function into a json response and sets the correct headers etc.)

When I hard refresh the page, I get a new nonce and my AJAX now works…

How can I force a new nonce to be returned, so that AJAX works without refreshing the page?

This post is kinda similar – Serving nonces through AJAX is not refreshing nonce, returning 403 error, but I can’t see anything in my code which is changing the user and invalidating the nonce…

Unless, the log in route – now logged in – changes the nonce, which doesn’t get returned?

0
Rob 3 months 0 Answers 8 views 0

Leave an answer