wp_verify_nonce return false despite correct parameter passed

the wp_verify_nonce() keep returning false

If you were logged-in to your (WordPress) site when you used the form, then the above is normal. Here’s why so:

  • Your form submits to a custom REST API endpoint (at /wp-json/ilms_plugin/new_membership) and the default authentication method used by the REST API is cookie-based, i.e. it checks if a nonce with the action named wp_rest is set and that it’s valid (not yet expired), and if not (not set or it’s invalid/expired), then WordPress sets the current user to 0 which affects all nonce-related functions including but not limited to wp_verify_nonce().

  • In simple words, it means functions like wp_verify_nonce() will return false because nonces are based on the current user, so if the user is logged-in to your site (when filling in the form), but not the REST API (when the form submission/data is processed), then wp_verify_nonce() will return false because the user ID becomes 0 in the REST API.

Check out the REST API handbook for more details about the authentication: https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/

How to fix the issue

Just add wp_nonce_field( 'wp_rest', '_wpnonce', false ); somewhere in your form, e.g. right after the opening <form> tag: (Note that I escaped the URL using esc_url())

<form action="<?php echo esc_url( get_rest_url( null, 'ilms_plugin/new_membership' ) ); ?>" ...>
    <?php wp_nonce_field( 'wp_rest', '_wpnonce', false ); ?>
    ...

Additional Notes

  1. Instead of get_rest_url( null, 'ilms_plugin/new_membership' ), you could use rest_url( 'ilms_plugin/new_membership' ) which uses rest_url() and is shorter.. 🙂

  2. Instead of using $wpdb->query(), I would use $wpdb->insert() to insert the data to the database.

  3. A REST API endpoint should always set a permission_callback and you should also use the args argument to define the parameters for the endpoint like the test_nonce in your case. Nonetheless, refer to Adding Custom Endpoints in the REST API handbook for further details.