Deprecated: preg_replace(): Passing null to parameter #3 ($subject) of type array|string is deprecated in /data/sites/web/remonpelnl/www/wp-content/themes/remonpel_nl__child__twentyfourteen/functions.php on line 32
WordPress REST-API nonce-sense. – Remons TechNotes

WordPress REST-API nonce-sense.

Working with the WordPress REST-API is HELL. There. I said it. It is powerful, it is secure, it is everything a developer needs, but for the love of [fill in your favorite deity here], WordPress, be consistent!

Using the REST-API requires authentication. Well, that’s not a problem. Just create a route to log-in and one to log-out. WordPress has functions to do that.


The first hurdle is getting the WordPress REST API to function. Oh, wait, you need a nonce ?! Well, thank you WordPress for this ‘security’-measure. For everything else in WordPress the authentication cookies you get when logging in to /wp-admin are enough, but for REST-API you need a nonce … the F why !?

Sorry, but this is just NONCE-SENSE! Pun intented. If only it were funny.

To get nonces to actually work, you need something like this:
(over simplified, please make sure you do this un-hackable ^^)

Somewhere in PHP

<?php add_action('wp_head', function(){
print '<script>window.nonce = '. json_encode(wp_create_nonce( 'wp_rest' )) .'</script>';
}); ?>

and in your application.js

$(document).ajaxSend(function (event, xhr, settings) {
xhr.setRequestHeader('X-WP-Nonce', window.nonce);

Now you can send the nonce to WordPress. Great. But then it works once you are already logged in or not. It stops working on a change of log-in status. After log-in, the nonce is no longer valid and a new nonce is needed. Same after log-out.

Simple solution: in your REST response, send a new nonce, and update the nonce-variable in javascript accordingly.

Somewhere in PHP

<?php add_filter( 'rest_post_dispatch', function( WP_REST_Response $response) {
$response->header('X-WP-Nonce', wp_create_nonce( 'wp_rest' )); return $response;
}, PHP_INT_MAX);?>

and in your application.js

$(document).ajaxComplete(function (event, xhr, settings) {
window.nonce = xhr.getResponseHeader('X-WP-Nonce');

But wait; just generating a new nonce will not work!

Why not?

on wp_signon(), WordPress sets new cookies. but WordPress only uses set_cookie() to do that. In other words; the new cookies are valid only on consequent page loads.
wp_create_nonce() uses the cookie-values in memory (PHP $_COOKIE) which … is NOT refreshed after log-in.
wp_logout() has the same issue. WordPress sends empty cookies, but does not update the local memory, again, requiring a page reload.


Do what WordPress should do, but doesn’t.

add_action('set_logged_in_cookie', function($cookie_value){
$_COOKIE[ LOGGED_IN_COOKIE ] = $cookie_value;
}, PHP_INT_MAX); add_action('clear_auth_cookie', function(){

With this, the used $_COOKIE variable is now identical to the cookie.

But this does not work… yet…


Well, wp_create_nonce() depends on more than just the cookie. It depends on the current-user also. The global variable $current_user holds the current user. So it would be safe to assume that on wp_signon(), that variable is updated, right? Well that assumption would be wrong!

wp_signon() does NOT set the global user object to the new user. And, failing consistently, wp_logout() does NOT invalidate the global user object.

Again, more hooks just to make WordPress do what it should do out of the box;

add_action('wp_login', function($login, $user){
wp_set_current_user( $user->ID );
}, PHP_INT_MAX, 2); add_action('wp_logout', function(){
wp_set_current_user( 0 );

The full code for your enjoyment:

P.s. I repeat: this code is perhaps not secure, perhaps over-simplified, but at least, with this, the REST-API is usable. The alternative is reverting to 1990s AJaX calls through wp-admin/admin-ajax.php.

Author: Remon Pel

WebDeveloper though not WebDesigner

9 thoughts on “WordPress REST-API nonce-sense.”

  1. Fantastic! I’ve not touched wordpress in… 10 or so years… I see it has a REST api… so thought I’d use it as a backend for an SPA…

    This whole nonce thing has been twisting my melon for the last 3 days. I’ve been banging my head against the wall (made worse because I’m terrible at PHP). Log in and log out just didn’t work.. subsequent ajax posts were failing. I couldn’t understand it… I just assumed it would work as your post described it should…

    Thank you for this code – I’ve dropped it in, and my REST api and SPA are talking to each other… thank you! Hugely helpful! :)

  2. I am struggling to implement refreshing nonces when using with REST API. Should I set the nonce_life to 30-90 days? As setting it 1 day will require user to login again and again.

    1. A nonce is only used to validate a form submission, to prevent spamming a form etc. It has no influence over the login lifetime. Nonces typically have a lifetime of 5 minutes, not hours and certainly not days or months.
      I’m guessing you have other issues in your login process, but unfortunately, this is not the place for that as I am only one person; you will be better off on one of the many forums out there, like or

      My example above works (or at least worked, when it was written) to refresh the nonce after login or logout, but, as said, does not change anything for how long a user is logged in or the automatic logout process (of which I never knew there was).

      Maybe it’s as simple as the login-cookies not being set properly? Again; try the power of the hive-mind ;)

      Good luck!

  3. By automatic logout, I meant if a user sets remember to true then the auth cookie is only valid for 14 days, which I extended using the ‘auth_cookie_expiration’ filter.

    WP Nonce documentation is quite tricky to understand.

    After trying your solution, I realised that new nonce gets generated after the half of its life i.e if nonce life is 24hrs and then we use the wp_create_nonce() after 12 hrs, it will generate a new nonce and the old one will still be valid till the completion of 24hrs from its generation time.

    To simplify the flow,
    whenever the REST API throws the ‘rest_cookie_invalid_nonce’ error we will already have the new Nonce in the response header of that error. So we just need to pass new Nonce and continue the GET/POST requests.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Confidental Infomation
stop spam mail