A nonce in WordPress gets misunderstood constantly, usually in one of two directions: people either skip it entirely because “it’s just a form on my own site,” or they treat it as a security token that authenticates the user, which it doesn’t do at all.
What a nonce actually verifies
A nonce confirms that the request came from a page WordPress itself generated recently — not that the user is who they say they are, and not that they’re allowed to do what they’re asking to do. Those are separate checks you still have to do yourself with current_user_can().
Creating and checking one
// In the form
wp_nonce_field('delete_item_action', 'delete_item_nonce');
// On submit
if (!isset($_POST['delete_item_nonce']) ||
!wp_verify_nonce($_POST['delete_item_nonce'], 'delete_item_action')) {
wp_die('Security check failed.');
}
if (!current_user_can('delete_posts')) {
wp_die('You do not have permission to do this.');
}
Both checks matter. A nonce without a capability check just proves the request came from your form — it says nothing about whether that particular user should be allowed to submit it.
Why nonces expire
By default they’re valid for roughly 24 hours in two overlapping 12-hour windows, which is why a form left open in a browser tab overnight sometimes fails on submit the next morning with a “link expired” message. That’s expected behavior, not a bug.
AJAX specifically
Pass the nonce via wp_localize_script() rather than hardcoding it, since a hardcoded nonce in a cached page becomes stale the moment the cache is served to a second visitor:
wp_localize_script('my-script', 'myAjax', [
'ajaxurl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('my_ajax_action')
]);
This is a small mechanism, but it’s the reason a malicious site can’t quietly submit forms on your WordPress site using a logged-in admin’s session without their knowledge.