title: Troubleshooting Wordpress nonce in AJAX call
body: <p>I'm using AJAX to check body class and conditionally fire one of 2 actions. If the Google Speech API is supported, a voice-search capable form loads. If it isn't, a regular search form loads.</p>
  
  <p>The <code>check_ajax_referer()</code> function is coming up 403, so there's something wrong with my nonce.</p>
  
  <p>The website is <a href="https://mercury.photo/contact/" rel="nofollow noreferrer">mercury.photo</a>. Code is simplified for clarity; I already know it works if I don't include the nonce check.</p>
  
  <p>In my script, I have:</p>
  
  <pre><code>//-------------------------------------------------*/
  // Speech Recognition
  //-------------------------------------------------*/
  
  jQuery(document).ready(function ($) {
    $(function () {
      // Add body class if browser supports Google Voice API
      if (Modernizr.speechrecognition) {
        $("body").addClass("voice-searchable");
      }
      var ajaxData;
      if ($("body").hasClass("voice-searchable")) {
        ajaxData = { "action": "my_voice" }
      } else {
        ajaxData = { "action": "my_novoice" }
      };
      xhr = new XMLHttpRequest();
      // Use a variable so we can callback 'done' and 'fail'; see https://medium.com/coding-design/writing-better-ajax-8ee4a7fb95f
      var ajaxCall = $.ajax({
        type: "POST",
        url: myVoiceSearch.ajaxurl,
        dataType: "html",
        data: ajaxData,
        security: myVoiceSearch.ajax_nonce
      });
      // 'success' &amp; 'error' promises are deprecated; use 'done' and 'fail' instead
      ajaxCall.done(function (data) {
        $(".breadcrumb_search").html(data);
      });
      ajaxCall.fail(function (data, xhr, ajaxOptions, thrownError) {
        var errorMsg = "Oh, bother. Your AJAX request failed with a status code of " + xhr.responseText + ".";
        console.log( errorMsg );
      });
    });
  });
  (window, jQuery, window.Window_Ready);
  // More scripts to load Google Voice API
  </code></pre>
  
  <p>And in <code>functions.php</code>, I enqueue my scripts and add the actions:</p>
  
  <pre><code>/*
   * Ajax scripts for speech recognition
   */
  
  add_action( 'wp_print_scripts', 'my_search_ajax_enqueue' );
  function my_search_ajax_enqueue() {
    if ( ! is_admin() ) { // Load the script only on the front end
      $protocol = isset( $_SERVER['HTTPS'] ) ? 'https://' : 'http://';
      wp_register_script( "my-search-ajax-script", get_stylesheet_directory_uri() . '/js/speech-input.js', array( 'jquery' ) );
  
      $params = array( 'ajaxurl' =&gt; admin_url( 'admin-ajax.php', $protocol), 'ajax_nonce' =&gt; wp_create_nonce( 'my-create-voice-search-nonce' ), );
  
      wp_localize_script( 'my-search-ajax-script', 'myVoiceSearch', $params );
  
      wp_enqueue_script( 'my-search-ajax-script' );
    };
  }
  
  /**
   *
   * Generate custom search form
   *
   **/
  
  function my_voice() {
    // This check fails
    check_ajax_referer( 'my-create-voice-search-nonce', 'security' );
    $form = 'A most excellent form, m&amp;rsquo;lord.';
    echo $form;
    wp_die();
  }
  
  add_action('wp_ajax_my_voice', 'my_voice');
  add_action('wp_ajax_nopriv_my_voice', 'my_voice');
  
  function my_novoice() {
    // check_ajax_referer( 'my-create-voice-search-nonce', 'security' );
    $form = 'Lame form, dude!';
    echo $form;
    wp_die();
  }
  
  
  add_action('wp_ajax_my_novoice', 'my_novoice');
  add_action('wp_ajax_nopriv_my_novoice', 'my_novoice');
  </code></pre>
  
  <ol>
  <li>How can I log whether the nonce is being seen in the AJAX call?</li>
  <li>What might be preventing the nonce from either being set (in my PHP), or received (in my AJAX)?</li>
  </ol>
  
  <p>EDIT: Did some more reading, and it appears the main function of WP nonces is to prevent CSRF, and as such, is really only useful for logged-in users. So, more questions:</p>
  
  <ol start="3">
  <li>Should I even bother with nonces on this AJAX call?</li>
  <li>Is there a better way to handle verifiying the call's authenticity?</li>
  </ol>
  
  <p>EDIT: Further reading confirms that I shouldn't even be doing this, since it's a front-end form. Closing this question, but feel free to comment/answer if you know what was wrong with my code — I always appreciate the opportunity to learn!</p>
  
  <p>EDIT: Answer given and accepted.</p>