Not getting wordpress nonce to work with wp-rest api application

Ronnie Zweers picture Ronnie Zweers · Feb 11, 2017 · Viewed 10.5k times · Source

I have an app which is should be secure and therefore using Nonce's but I can't get them to work. I have tried several options but apparently something is missing as the validation doesn't work.

My js code fragment is:

function placeNew(next){
  _nonce = $('input#_nonce').val();
  request = $.ajax({
    type: 'POST',
    url: url_path + '/foo/v1/newbee',
    data: {bid : next , _nonce : _nonce},
    security: '<?php echo wp_create_nonce( "a" ); ?>',
    dataType: 'json'
});
request.done(function (response, textStatus, jqXHR){
  str = JSON.stringify(response);
  if(response["error"]){
    alert(response["message"]);
  }

The nonce is added to the page with the following code:

$nonce = wp_create_nonce( 'a' );
echo "<input type='hidden' id='_nonce' value=" . $nonce ."/>";

Within php the following function fragment is used to get and compare the nonce:

function ace($request) {
    global $wpdb;
    $timestamp = time();
    $nonce = (string) $request['_nonce'];
    $verify = check_ajax_referer( 'a', $nonce, false );
    if ( ! $verify){
        $errMsg = $nonce . '-'. $verify .' not validated ';
        return (object) array(error => true, message => $errMsg);
    }

I always do get the message "not validated". $nonce has a value but $verify never gets a value.

Answer

Jeremy picture Jeremy · Apr 6, 2017

According to the docs:

For developers making manual Ajax requests, the nonce will need to be passed with each request. The API uses nonces with the action set to wp_rest. These can then be passed to the API via the _wpnonce data parameter (either POST data or in the query for GET requests), or via the X-WP-Nonce header.

The important part you are missing is:

The API uses nonces with the action set to wp_rest.

For it to work, you must name your action in the wp_create_nonce to wp_rest.

So for your code, you must change all instances of:

wp_create_nonce( "a" )

to

wp_create_nonce( 'wp_rest' )

Also, as the docs state:

Supplying the nonce as a header is the most reliable approach.

So adding this to your ajax is simple and looks something like:

var _nonce = "<?php echo wp_create_nonce( 'wp_rest' ); ?>";
$.ajax({
    type: 'POST',
    url: url_path + '/foo/v1/newbee',
    data: {
        bid : next
    },
    dataType: 'json',
    beforeSend: function ( xhr ) {
        xhr.setRequestHeader( 'X-WP-Nonce', _nonce );
    }
});

Also, to fix the check

check_ajax_referer( 'a', $nonce, false )

Should now be

check_ajax_referer( 'wp_rest', '_nonce', false )