I am generating a nonce to be used with client side fetch requests to the rest api:
function prepAllAdminScripts() {
wp_register_script(
'reactAdminArea'
, PLUGIN_FOLDER_URL . 'shared/adminArea.bundle.js'
, null
, null
, true
);
wp_localize_script('reactAdminArea', 'serverParams', [
'_wpnonce' => wp_create_nonce('wp_rest')
, 'apiBaseUrlFromWp' => get_rest_url()
]);
wp_enqueue_script('reactAdminArea');
}
add_action('admin_enqueue_scripts', 'prepAllAdminScripts');
As the fetch request is fired, I see it go into an auth handler function. The nonce value shows as a string and appears to be a matching nonce value but it fails:
protected function authUserOrRespondWithError($clientNonce) { // 3a730<partially removed>
$verification = wp_verify_nonce($clientNonce); // false
if ($verification === false) {
wp_send_json(['error' => "Failed nonce verification"]); // sends back to the client
}
}
When I check the nonce value in the Chrome browser console, it matches exactly.
Does anyone know why the verification is returning false here?
Update
Here is how I am sending the nonce data back to the API:
const fetchAllCoupons = async () => {
try {
const response = await fetch(`${apiBaseUrl}/pluginFolder/1.0/loadAll`, {
method : 'post',
headers : {
'Content-Type' : 'application/json'
},
body : JSON.stringify({clientNonce})
});
let data = await response.json();
if (data && 'error' in data) {
setSnackbarMessage(data.error)
}
return data;
}
catch (e) {
console.log(e, `=====error=====`);
}
};
Here is the route handler:
public function registerLoadCouponRoute() : void {
register_rest_route($this->urlBase, 'loadAll', [
'methods' => ['get', 'post'],
'callback' => [$this, 'respondAllCoupons']
]);
}
Here is the first part of the callback that contains authUserOrRespondWithError
:
public function respondAllCoupons(\WP_REST_Request $request) {
global $wpdb;
$clientNonce = $request->get_param('clientNonce');
$this->authUserOrRespondWithError($clientNonce);
I am generating a nonce to be used with client side fetch requests to the rest api:
function prepAllAdminScripts() {
wp_register_script(
'reactAdminArea'
, PLUGIN_FOLDER_URL . 'shared/adminArea.bundle.js'
, null
, null
, true
);
wp_localize_script('reactAdminArea', 'serverParams', [
'_wpnonce' => wp_create_nonce('wp_rest')
, 'apiBaseUrlFromWp' => get_rest_url()
]);
wp_enqueue_script('reactAdminArea');
}
add_action('admin_enqueue_scripts', 'prepAllAdminScripts');
As the fetch request is fired, I see it go into an auth handler function. The nonce value shows as a string and appears to be a matching nonce value but it fails:
protected function authUserOrRespondWithError($clientNonce) { // 3a730<partially removed>
$verification = wp_verify_nonce($clientNonce); // false
if ($verification === false) {
wp_send_json(['error' => "Failed nonce verification"]); // sends back to the client
}
}
When I check the nonce value in the Chrome browser console, it matches exactly.
Does anyone know why the verification is returning false here?
Update
Here is how I am sending the nonce data back to the API:
const fetchAllCoupons = async () => {
try {
const response = await fetch(`${apiBaseUrl}/pluginFolder/1.0/loadAll`, {
method : 'post',
headers : {
'Content-Type' : 'application/json'
},
body : JSON.stringify({clientNonce})
});
let data = await response.json();
if (data && 'error' in data) {
setSnackbarMessage(data.error)
}
return data;
}
catch (e) {
console.log(e, `=====error=====`);
}
};
Here is the route handler:
public function registerLoadCouponRoute() : void {
register_rest_route($this->urlBase, 'loadAll', [
'methods' => ['get', 'post'],
'callback' => [$this, 'respondAllCoupons']
]);
}
Here is the first part of the callback that contains authUserOrRespondWithError
:
public function respondAllCoupons(\WP_REST_Request $request) {
global $wpdb;
$clientNonce = $request->get_param('clientNonce');
$this->authUserOrRespondWithError($clientNonce);
Share
Improve this question
edited Sep 8, 2019 at 9:57
Sean D
asked Sep 5, 2019 at 21:45
Sean DSean D
3878 silver badges21 bronze badges
2
- 1 How are you sending the nonce? From the URL as a query param and how you capture it in your REST API? – Roel Magdaleno Commented Sep 6, 2019 at 0:00
- @RoelMagdaleno I send it in the post body of a fetch request. I have updated the original post to show the request handler. I capture it with a rest route handler using the callback shown. As mentioned, I can see the value arrives and is correct – Sean D Commented Sep 6, 2019 at 6:59
1 Answer
Reset to default 2First, nonce for an action is the same when the user is not authenticated/logged-in. (because the user ID is always 0
)
Secondly, you're getting false
because you didn't specify the nonce action which is wp_rest
in your case:
// Correct usage - a valid action name is set (wp_rest).
wp_verify_nonce( $clientNonce, 'wp_rest' );
// Incorrect usage - empty action; always returns false.
wp_verify_nonce( $clientNonce );
And if you are actually trying to authenticate the request using the standard cookie authentication, then you should use the X-WP-Nonce
header to send the nonce and not the request body
/payload:
const fetchAllCoupons = async () => {
try {
const response = await fetch(`${apiBaseUrl}/pluginFolder/1.0/loadAll`, {
method: 'post',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': clientNonce // <- here, send the nonce via the header
},
body: JSON.stringify({
// WordPress will not use this when verifying the associated user in the request.
clientNonce,
// but WordPress will not use this, either. Because we're sending a JSON payload.
_wpnonce: clientNonce
})
});
...
} catch (e) {
...
}
};
Or you can also send the nonce as a query string (in the URL) like so:
`${apiBaseUrl}/pluginFolder/1.0/loadAll?_wpnonce=` + clientNonce