I would like my dev server on http://localhost:8080 to work with my wordpress install's rest api, of which the api base url is at http://localhost/wptest2/index.php/wp-json/ I am currently getting the title error when I try to make requests through the dev server:

Access to fetch at 'http://localhost/wptest2/index.php/wp-
 from origin 'http://localhost:8080' has been blocked
 by CORS policy: Request header field x-wp-nonce is not
 allowed by Access-Control-Allow-Headers in preflight response.

In my plugin's entry file I have the following:

function add_cors_http_header() {
  header("Access-Control-Allow-Origin: *");
add_action('init', __NAMESPACE__ . '\\' . 'add_cors_http_header');

I thought this would enable cross domain requests but apparently it is not enough, at least for x-wp-nonce.

Is there anything more that can be done to enable the dev server to accept my nonce header?


There is no change after adding Access-Control-Allow-Headers : * to the cors setting function:

function add_cors_http_header() {
  header("Access-Control-Allow-Origin: *");
  header("Access-Control-Allow-Headers: *");
  header("Access-Control-Max-Age: *");

Update 2

Here is the OPTIONS request:

Options Request

Update 3

Now the X-WP-Nonce header is set to append instead of replace, the function is hooked to rest_pre_serve_request, and it's added as a filter instead of action:

function add_cors_http_header() {
  header("Access-Control-Allow-Origin: *");
  header("Access-Control-Allow-Headers: X-WP-Nonce", false);
add_filter('rest_pre_serve_request', __NAMESPACE__ . '\\' . 'add_cors_http_header');

I now get 403 Forbidden

I have copied the cookie name wordpress_logged_in_69cb7e12fd<removed> and its value to the dev server domain at localhost:8080 but this does not change the response.

Update 4

The nonce I use is freshly copied from my wordpress session in another tab that creates the nonce and localizes it into the react.js app. This React.js script file is built using npm run build and hooked to admin_footer. It is a slightly older version of the script.

The newest React.js script is in another tab on localhost:8080 The nonce is put into React manually and sent as a request like so:

// globals.js
// this file is loaded by index.jsx, the top level component file

global.clientNonce = "5d6352af1d";

// in Chrome browser, tab open to localhost:8080
console.log(clientNonce) // "5d6352af1d"

// ViewCoupons.jsx, back in the IDE
// this file is loaded by index.jsx. clientNonce is passed down as a prop

const fetchAllCoupons = async (limit, offset) => {
    try {
      const response = await fetch(`${apiBaseUrl}/${namepaceAndVersion}/load?limit=${limit}&offset=${offset}`, {
        method : 'get'
        , headers : {
          'X-WP-Nonce' : clientNonce
      let data = await response.json();

      if (data && 'error' in data) {

      return data;
    catch (e) {
      // console.log(e, `=====error=====`);
      throw e;

2nd request


  • 2
    The init hook is too early - WordPress overwrites the header later. Try with the rest_pre_serve_request filter (but make sure to return the first function parameter) - e.g. header( 'Access-Control-Allow-Headers: X-WP-Nonce', false );
    – Sally CJ
    Sep 18, 2019 at 11:30
  • 1
    Did you send the proper X-WP-Nonce value? Is it actually still valid for the user? Can you post a screenshot of the request and response? And what's the code you use for making the request?
    – Sally CJ
    Sep 18, 2019 at 15:33
  • 1
    Also, although this may not fix the issue, you should return the first parameter passed to your add_cors_http_header function - function add_cors_http_header( $served ) { /* ... */ return $served; }
    – Sally CJ
    Sep 18, 2019 at 15:36
  • 1
    Ok, thanks, but instead of trying hard to send the cookie nonce, and as I've said, consider using an authentication plugin which doesn't require you to use the X-WP-Nonce header or the _wpnonce query.
    – Sally CJ
    Sep 18, 2019 at 17:39
  • 2
    Yes, it is. Sorry, I didn't really notice the ports. But anyway, I deleted that comment and once again, try - or go with - an authentication plugin. That should work and should answer your other question. Cheers.
    – Sally CJ
    Sep 18, 2019 at 19:02


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.