Handling Nonces in WordPress
Tags: wordpress, php, security
Published: 2021-08-30 21:46:40

---
title: Handling Nonces in WordPress
published: true
date: 2021-08-23 10:00:00 UTC
tags: wordpress,php,security
canonical_url: https://indexforwp.com/handling-nonces-in-wordpress/
---

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.

```php
$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

```php
$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.

```php
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&amp;paged=1&amp;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

```php
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

```php
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.

```php
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:

```php
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

```js
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**

{% user david_woolf %}