0

I'm having trouble validating a nonce created with wp_create_nonce() inside a hidden input with the name nonce in an html form:

<input type="hidden" name="nonce" value="<?php echo wp_create_nonce('action_name'); ?>" />

The form submission is done via ajax and validated with check_ajax_referer('action_name','nonce'). This always returns -1. All REST endpoints have been tested without nonces and work 100% fine.

The issue seems to stem from wp's user identifcation.

My debugging so far

Nonce creation
Within wp-includes/pluggable.php wp_create_nonce('action_name') creates a nonce hashing various variables including the user id and the action.

Ajax call
I submit an ajax call which calls check_ajax_referer('action_name','nonce'). This in turn calls wp_verify_nonce($nonce,$action) which verifies the nonce by hashing the same variables and comparing the two.

Reverse engineering to locate problem
My problem is that wp_create_nonce('action_name') is being created with the correct user id. However, when I run check_ajax_referer('action_name','nonce') which calls wp_verify_nonce($nonce,$action) which in turn calls wp_get_current_user(); no user is found (user id is 0).

Evidence the problem is to do with user id

If I temporarily edit wp-includes/pluggable.php to force my user id, the nonce validation works fine. It's as if ajax requests to a known and valid endpoint are being treated as if the user is logged out regardless of whether they are or not.

I'm clearly missing something here, but I have no idea what.

If it helps, this is the REST point registration. As mentioned it works fine without the involvement of a nonce.

    register_rest_route(
        'my-namespace', //namespace
        'my-namespace-route-1', //route
        ['methods'=>'POST',
         'callback'=>['Another_Class',//class
             'a_static_function'] //static function
        ] //params
    );
  • i don't see the code for your AJAX endpooint can you edit your question to include it? Is there a reason you went for the old admin-ajax.php api rather than the a newer REST API endpoint via register_rest_route? – Tom J Nowell Sep 19 at 0:32
  • I added an example. I think this is the newest API right? – dewd Sep 19 at 0:52
1

This is happening because a separate nonce with the action wp_rest is not being sent by the server to the client and received back from the client in an HTTP request header called X-WP-Nonce with every REST request.

To get this working, you will have to generate a nonce like this:

wp_create_nonce('wp_rest')

...and provide it to the client making the rest call. Once your client has the nonce value, you need to add it to every REST request e.g.:

headers: {
    'X-WP-Nonce': nonce,
}

Creating the nonce on the server and accessing it on the client can be done several ways. Using wp_localize_script() is the most common and probably best practice for WordPress. wp_localize_script() addds a global variable to the client for a script to access. See https://developer.wordpress.org/reference/functions/wp_localize_script/.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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