Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
WordPressJune 22, 20264 min read

WordPress Nonces: How to Secure Forms and AJAX Requests

WordPress nonces provide essential CSRF protection for your site. Learn how to use wp_create_nonce and verify requests to keep your forms and AJAX secure.

WordPressSecurityCSRFAJAXPHPWeb DevelopmentTutorial

Last month, I spent about two days auditing a client’s custom plugin because users were reporting weird data shifts in their profiles. It turned out the forms lacked any verification, meaning a malicious site could trick an authenticated admin into submitting requests on their behalf. That’s a classic Cross-Site Request Forgery (CSRF) attack, and WordPress nonces are your first line of defense against it.

What is a WordPress nonce?

A nonce stands for "number used once." In the WordPress ecosystem, it’s a unique token generated by the server to ensure that a request originated from your site, not a third-party attacker. It isn't a silver bullet for total security—like CSRF protection that you understand and can implement today explains—but it’s an essential layer for validating user intent.

Crucially, nonces are tied to the user session and a specific action. If an attacker tries to replicate your form submission, their token won't match the one WordPress expects for that specific user and task.

Creating and verifying nonces

When you build a form, you need to inject a hidden field that holds the token. You use wp_nonce_field() for this.

PHP
<form method="post" action="process-data.php">
    <?php wp_nonce_field('my_custom_action', 'my_nonce_field'); ?>
    <!-- Your form inputs here -->
    <input type="submit" value="Submit">
</form>

The first argument, 'my_custom_action', is an arbitrary string that acts as a namespace. Always make this specific to the action being performed. On the server side, you verify it like this:

PHP
if (isset($_POST['my_nonce_field']) && wp_verify_nonce($_POST['my_nonce_field'], 'my_custom_action')) {
    #6A9955">// Process your data safely
} else {
    wp_die('Invalid nonce. Security check failed.');
}

Securing WordPress AJAX requests

If you're building a modern interface, you're likely using WordPress AJAX. This is where things get tricky. You can't just drop a hidden field into a static HTML form because the request is triggered via JavaScript.

We first tried passing the nonce as a global JavaScript variable using wp_localize_script(). It worked, but it felt messy to manage dozens of global variables for different features. A cleaner approach is to use a data attribute on the trigger element or a specific meta tag in the header.

Here is the standard workflow:

  1. Generate the token in PHP:

    PHP
    $nonce = wp_create_nonce('ajax_action_name');
    wp_localize_script('my-script-handle', 'wpApiSettings', [
        'nonce' => $nonce
    ]);
  2. Send it in your AJAX request:

    JAVASCRIPT
    fetch(CE9178">'/wp-admin/admin-ajax.php', {
        method: CE9178">'POST',
        body: new URLSearchParams({
            action: CE9178">'my_ajax_handler',
            nonce: wpApiSettings.nonce
        })
    });
  3. Verify it in your handler:

    PHP
    check_ajax_referer('ajax_action_name', 'nonce');

The check_ajax_referer() function is a helper that wraps wp_verify_nonce() and automatically calls wp_die() if the check fails. It saves you a few lines of boilerplate code and ensures you don't forget to handle the failure case.

Common mistakes to avoid

  • Reusing nonce names: Never use the same nonce string for different actions. If an attacker intercepts a nonce for delete_post, they shouldn't be able to use it for update_user_email.
  • Assuming nonces are authentication: A nonce does not prove who the user is; it only proves they are who they say they are within a valid session. Always combine it with capability checks like current_user_can('edit_posts').
  • Ignoring the expiry: By default, WordPress nonces are valid for 24 hours (roughly), but the window of validity actually changes based on the user's login session. Don't rely on them as long-term tokens.

FAQ

Are nonces enough to stop all CSRF? No. They prevent an attacker from tricking a user into submitting a form. They don't protect against SQL injection (use WordPress Database Queries: Securely Using $wpdb and Preparing SQL for that) or XSS.

Can I use the same nonce for every request? Technically, yes, but you shouldn't. Using the same nonce for multiple actions increases the window of opportunity for an attacker to hijack a request.

What happens if the nonce expires? The wp_verify_nonce() function will return false. Your code should handle this gracefully by prompting the user to refresh the page or re-submit the form, rather than just showing a broken interface.

Final thoughts

Implementing WordPress security via nonces is a habit that separates hobbyists from professionals. It’s annoying to add these checks every single time, but the payoff is a site that doesn't get compromised because of a simple form submission. Next time, I might look into automating nonce injection for all forms via a base class, but for now, I prefer the explicit approach—it's easier to debug when something goes wrong.

Back to Blog

Similar Posts

WordPressJune 22, 20264 min read

Mastering the WordPress User Object: WP_User Class Deep Dive

The WordPress user object acts as the engine for authentication and authorization. Learn how to leverage the WP_User class to manage roles and capabilities.

Read more
WordPressJune 22, 20264 min read

WordPress Plugin Activation: A Developer’s Guide to Lifecycle Hooks

WordPress plugin activation happens in a specific sequence. Learn how to use register_activation_hook to handle setup tasks during the development lifecycle.

Read more
WordPressJune 22, 20264 min read

WordPress Database Queries: Securely Using $wpdb and Preparing SQL

Master WordPress database queries with the $wpdb class. Learn how to use prepared statements for SQL injection prevention and secure your custom data.

Read more