1

I have trouble with wp_create_nonce() and wp_verify_nonce().

The root of my problem is both the way nonces are created and the place where I generate nonces.

Looking at the codes of wp_create_nonce() and wp_verify_nonce(), I see that nonces are a hash value created from multiple factors including $uid, which is a user id of current user.

$user = wp_get_current_user();
$uid = (int) $user->ID;
if ( ! $uid ) {
    /** This filter is documented in wp-includes/pluggable.php */
   $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );

}
$token = wp_get_session_token();
$i = wp_nonce_tick();
return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 ); 

I create the nonce under REST API and verify the nonce in normal page. However, I also find that $uid becomes 0 in REST API (dunno why, but somewhere I saw this and tested it myself. Yes, there's no user id inside REST). So, the $uid in my REST function and the $uid in my page become different.

[1] I create _wpnonce in REST API. Below is a pseudo-code for my function in REST.

add_action( 'rest_api_init', function() {
    register_rest_route( 'view/', '/customers/', array(
        'methods' => 'POST',
        'callback' => 'fnc_view_customer_in_table_format'
    ));
});

if( !function_exists( 'fnc_view_customer_in_table_format' ) ) {
    function fnc_view_customer_in_table_format(WP_REST_Request $request ) {

    //*** Code omitted on purpose ***

    $data .= '<form action="'. get_the_permalink( $post->ID ) .'" id="_form-view" name="_form-view" method="post">';
    $data .= '<input type="hidden" id="_wpnonce" name="_wpnonce" value="'. wp_create_nonce( 'view_post-'. $post->ID ) .'" />';
    $data .= '<input type="hidden" id="_post_id" name="_post_id" value="'. $post->ID. '" />';
    $data .= '<input type="submit" class="btn btn-sm btn-link" value="'. get_the_title( $post->ID ) .'">';
    $data .= '</form>';

    //*** Code omitted on purpose ***

    $result = array( 'msg' => $data, 'error' => false );
}

[2] Above $data is returned as a response and is echoed in normal page. And I verify the nonce here. This is a normal wordpress page.

<?php
get_header();

$wpnonce = $_REQUEST['_wpnonce'];
$post_id = $_REQUEST['_post_id'];
if( !wp_verify_nonce( $wpnonce, 'view_post-'. $post_id ) ) {
    die( 'Security check' );
}

?>

//*** Omitted: HTML Codes ***

<?php
get_footer();

So, I presume that the only solution is let Wordpress REST recognize current_user. How do I achieve this, or am I thinking the wrong way?

** EDIT ** As a workaround, I changed my wp_verify_nonce process as below.

// nonce is created in REST API, which doesn't have UID
// In order to replicate the same, set UID to 0 here
$uid = (int) wp_get_current_user()->ID;
wp_set_current_user(0);

// Nonce check
if( !wp_verify_nonce( $wpnonce, 'view_post-'. $post_id ) ) {
die( 'Security check' );
}

// Now get the current user back in place
wp_set_current_user( $uid );

Anyways, this doesn't look beautiful. What would be a better practice to solve my problem?

  • Could elaborate on where your code [2] lives? Is it hooked onto an action? If so, which? (It doesn't appear as you're using WordPress' REST API however). – Stephen Harris May 12 '17 at 11:25
  • I have a page (let's say page A) that calls the REST function fnc_view_customer_in_table_format() and echoes the response, which is basically a HTML code for <form></form>. Once the <form> is submitted, page [2] is called and the nonce is verified in page [2]. – Dongsan May 12 '17 at 15:37
0

I know it pasts a long time of this question.

But I had the same issue and it was difficult for me to find some documentation about it. I had the same problem, for some reason wp_create_nonce and wp_verify_nonce they bot retrieve different hash. So I notice the problem was the $User->ID or $uid that these two function uses to hash the nonce.

I just trying to create the nonce inside the script but for some reason the uid become 0, and what I did, is to create the nonce before and outside the script block and print the value inside the script.

First it was like this (WRONG):

  var action     = 'submit_user_review';                  
  var ajax_nonce = '<?php echo wp_create_nonce('security'); ?>';

  jQuery.ajax({
       url: my_ajax_object.ajax_url,
       type: 'POST',
       data: {
           action: action,
           listing_id: rest_id,
           review: comment,
           rate: rate,
           security_review: ajax_nonce,
       },
       beforeSend: function() {
           // Show full page LoadingOverlay
           jQuery.LoadingOverlay("show");
      },            

and after like this (GOOD):

  <?php //Set Your Nonce
      $ajax_nonce_review = wp_create_nonce( "submit-user-review" );
  ?>
  <script>                  
  var action = 'submit_user_review';

  jQuery.ajax({
       url: my_ajax_object.ajax_url,
       type: 'POST',
       data: {
           action: action,
           listing_id: rest_id,
           review: comment,
           rate: rate,
           security_review: '<?php echo $ajax_nonce_review; ?>',
       },
       beforeSend: function() {
           // Show full page LoadingOverlay
           jQuery.LoadingOverlay("show");
      }, 

And that fix my problem, literally spend one day trying to figure it out this.

I hope it helps somebody else.

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.