2

I have a headless install of Wordpress on v5.4.0. The frontend can't GET any post that is in draft status, though when accessing the API url directly the data is returned without an issue. I'm assuming this is cookie/auth related. Note, I'm dynamically grabbing the nonce values from the backend, showing full strings here for the sake of argument. Here's my setup and screenshots of the responses:

Request URL: http://wordpress.test/wp-json/wp/v2/pages/19060?wpnonce=23c01b3b12&_embed=true

Called on the frontend using isomorphic-unfetch (also tried with axios) like so:

fetch("http://wordpress.test/wp-json/wp/v2/pages/19060?wpnonce=23c01b3b12&_embed=true", {
  credentials: "include"
})

Here's the request/response from the frontend, which is not working (this does work for all published content):

With this body:

{
  "code":"rest_forbidden",
  "message":"Sorry, you are not allowed to do that.",
  "data":{
  "status":401
  }
}

When trying to access the data directly, I see two different responses depending on the wpnonce query parameter underscore:

This works (using _wpnonce) returning the proper JSON data:

http://wordpress.test/wp-json/wp/v2/pages/19060?_wpnonce=23c01b3b12&_embed=true

Details:

This does not (using wpnonce):

http://wordpress.test/wp-json/wp/v2/pages/19060?wpnonce=23c01b3b12&_embed=true

Details:

Returns the same response error that the frontend does:

{
  "code":"rest_forbidden",
  "message":"Sorry, you are not allowed to do that.",
  "data":{
  "status":401
  }
}

EDIT:

I've also tried the X-WP-Nonce header mentioned here (https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/) and it doesn't seem to be recognized:

fetch(postUrl, {
  credentials: "include",
  headers: {
    "X-WP-Nonce": wpnonce
  }
})

{"code":"rest_cookie_invalid_nonce","message":"Cookie nonce is invalid","data":{"status":403}}

EDIT 2:

On a clean install of WP and a new barebones frontend (html + jquery) I'm seeing the same issue. However, I find that the nonce is valid when generating the preview link, but invalid when WP tries to verify using rest_cookie_check_errors. How can the same nonce with the same action (wp_rest) fail verification?:

I'm seeing that wp_get_session_token() is failing because there's no cookie found on REST requests. (https://core.trac.wordpress.org/browser/tags/5.4/src/wp-includes/pluggable.php#L2140) Isn't the point of the nonce to not require cookies? Could it be an issue with cross-domain cookie paths?

I am sending credentials in the XHR. Here's my frontend test code:

// GET page with Nonce header
$.ajax({
  url: postUrl,
  method: "GET",
  xhrFields: {
    withCredentials: true
  },
  beforeSend: function(xhr) {
    xhr.setRequestHeader("X-WP-Nonce", wpnonce);
    xhr.setRequestHeader("Content-Type", "application/json");
  }
})

Two questions:

  1. Mainly, how can I get draft post data using nonce values from the frontend?
  2. Why in the world would the _wpnonce / wpnonce query vars show different results on the frontend and backend?
  • 1
    Please review the documentation for authentication with the REST API: developer.wordpress.org/rest-api/using-the-rest-api/… Both your questions are answered. – Jacob Peattie Apr 2 at 0:17
  • Edited to note the X-WP-Nonce header in the get request. Am I missing something else? – theLucre Apr 2 at 0:45
  • It sounds like your nonce is recognised, but is invalid, are you sure it's generated correctly? – Tom J Nowell Apr 2 at 0:48
  • 1
    @theLucre, if you originally mentioned 'from external domain' in the question, I would've just suggested you to use an authentication plugin (just like JWT) because from remote apps, that's what the WordPress core suggests. After all, I don't think it's a good idea to include the cookies in the request (the credentials: 'include' in fetch()). – Sally CJ Apr 2 at 22:57
  • 1
    Thanks @SallyCJ. I assumed headless WP meant two domains. Apologize for any confusion and I appreciate your help! – theLucre Apr 3 at 3:08
1

Ok, so technically I didn't solve the issue that prevented me from accessing posts in draft status from an external domain where the frontend is hosted using only nonce values. My guess is that the logged_in cookie was not set/could not be read on the frontend side to verify the nonce value during an external AJAX request.

That being said, I installed the JWT Authentication for the WP REST API plugin (https://github.com/Tmeister/wp-api-jwt-auth) and now require admins to login once on the frontend preview page to set the token in local storage.

| improve this answer | |
  • You did solve it. That's the only solution. You cannot access cookies across domains, and as noted in the documentation that I linked you in the very first comment: "It is important to keep in mind that this authentication method relies on WordPress cookies. As a result this method is only applicable when the REST API is used inside of WordPress and the current user is logged in. In addition, the current user must have the appropriate capability to perform the action being performed." – Jacob Peattie Apr 3 at 2:21

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.