WordPress provides an easy to use nonce system to create and verify unique hashes for certain actions. Note that WordPress uses the word nonce to refer to a security token but they aren’t true nonces. Here is how WordPress defines their use of nonce:
WordPress’s security tokens are called “nonces” (despite the above-noted differences from true nonces) because they serve much the same purpose as nonces do. They help protect against several types of attacks including CSRF, but do not protect against replay attacks because they aren’t checked for one-time use. Nonces should never be relied on for authentication, authorization, or access control. Protect your functions using current_user_can(), and always assume nonces can be compromised.
While there are plenty of times that using a nonce is not appropriate, some examples of good use cases for nonces are:
- clicking a link that would alter the database
- submitting a form that would alter the database
- using WordPress’s REST API to perform POST, PUT, or DELETE actions
Note: a nonce is valid for 24 hours, and is not a one-time use code. This is why WordPress doesn’t consider their version true nonces.
How to create a nonce
There are a couple of ways to create nonces in WordPress, depending on where you are placing the nonce:
Generate a nonce code by itself
The most basic option is wp_create_nonce
which will give you the nonce value. I find this useful for passing a nonce to a REST API endpoint as a header.
$nonce = wp_create_nonce($action); // can be a string or integer
// example:
$nonce = wp_create_nonce('trash-post-23');
// outputs: 5817bdf2ac
Generate a url with a nonce parameter
Next, we have wp_nonce_url which takes a base URL, the nonce action name, and the name of the parameter (defaults to _wpnonce). This will return a full URL with the nonce appended as a URL parameter
$url_with_nonce = wp_nonce_url($url, $action, $name);
// example:
$url_with_nonce = wp_nonce_url('<https://localhost>', 'trash-post-23', '_wpnonce');
// outputs: <https://localhost?_wpnonce=5817bdf2ac>
Generate a hidden input with a nonce name and value
Finally, we have wp_nonce_field which is a quick way to output a hidden field with the nonce value. It also will add the referrer URL so you can verify the user came from the previous page and has a valid nonce.
wp_nonce_field($action, $name, $referer, $echo);
// example:
wp_nonce_field('trash-post-23');
// outputs:
// <input type="hidden" id="_wpnonce" name="_wpnonce" value="5817bdf2ac">
// <input type="hidden" name="_wp_http_referer" value="/wp-admin/plugins.php?plugin_status=all&paged=1&s">
How to verify a nonce
When working inside the WordPress dashboard, you can quickly verify a nonce and referrer by calling check_admin_referer
. By default, you need to pass in the action name. If you changed the nonce parameter name (defaults to _wpnonce
), you can pass that in as a second parameter
check_admin_referer($action, $name);
// example:
check_admin_referer('trash-post-23');
When working with async requests, you have a couple of options:
check_ajax_referer
The check_ajax_referer
function will handle verification and stop processing the request
check_ajax_referer($action);
// example:
check_ajax_referer('trash-post-23');
wp_verify_nonce
The wp_verify_nonce
function will handle verification but it is up to you to return an error. It’s recommended to return a 403: Forbidden error.
wp_verify_nonce($nonce, $action);
// example:
wp_verify_nonce('5817bdf2ac', 'trash-post-23'); // the nonce itself would be passed to the request and verified from the body or parameter list
Using nonces with REST API requests
If you are creating your own API requests in WordPress (for example: with fetch) and you want to submit requests using POST, PUT, or DELETE, then you will have to pass a nonce value. Fortunately, this is pretty easy if you are enqueuing your javascript files correctly.
When using wp_enqueue_script
you can pass another function called wp_localize_script
with any data you want to be accessible from that file:
wp_enqueue_script(
'ndx-script',
$path,
[],
'1.0.0',
true
);
wp_localize_script(
'ndx-script',
'wp_api',
[
'nonce' => wp_create_nonce('wp_rest')
]
);
Basically, you reference the name of your enqueued script, set your own variable name to use in javascript, and then pass an array of options. This will then provide you a global object in javascript. Here is how you would use the nonce in a fetch statement
fetch(PATH, {
headers: {
'X-WP-Nonce': wp_api.nonce
},
method: 'POST',
body: JSON.stringify({ name: value })
})
.then(response => response.json())
.then(response => {
// do something here
})
The only important part of this is the headers option in the second parameter of the fetch statement, passing the nonce. Custom headers always start with X
and then WP-Nonce
is defined by WordPress itself and what they’ll look for.
What’s great about this pattern is that you don’t need to verify the nonce in your rest endpoint. The system takes care of that for you and will return a 403: Forbidden error if you try to submit something without a nonce
Note: publicly consumable API endpoints do not require this which is why you can fetch a list of posts right from your browser in the URL field.
Wrap up (and a note on security)
Once again, it’s important to note that nonces should not be used in place of proper authentication. They are simply an extra check to prevent authenticated users from performing an action they didn’t intend to.
With the REST API especially, the nonce example here is only for requests sent while a user is logged in, and your endpoints should also use the permissions callback to check if the current user can perform the intended action.
I would also recommend you use the nonce functions that take care of some of the heavy lifting for you (like creating and verifying hidden fields with the nonce value).
Author
Top comments (0)