I'm new to the services and rest_server modules (and RESTful APIs altogether.) As I understand it though, the steps are basically this:

  1. Send a post request to /api/user/login with the username and password set in data
  2. Store the token you get in the response
  3. On subsequent post requests, add the token to the header with the key X-CSRF-TOKEN

When I use the Postman Chrome extension to do that, it works great. When I do it in code, it does api/user/login fine, I get the token, but when I try to access /api/other/endpoint, I get 403 Access denied for user anonymous error.

The first request (/user/login) looks like this:

POST /api/user/login HTTP/1.0
Content-Type: application/json
Accept: application/json
User-Agent: Drupal (+http://drupal.org/)
Host: mysiteurl.com
Content-Length: 41


And the second request (/other/endpoint) looks like this:

POST /api/other/endpoint HTTP/1.0
Content-Type: application/json
Accept: application/json
User-Agent: Drupal (+http://drupal.org/)
Host: mysiteurl.com
Content-Length: 0

If I make requests to /user/token after authenticating, I get new tokens each time. If I try to logout immediately after logging in (and send along that token), I get a "406 Not Acceptable : User is not logged in." error. it tells me user is not logged in.

If I check the site though, it shows the user as successfully having logged in, and still being logged in after the fact.

Do I have to save/send anything regarding the session name/id or cookie? Everything I've been looking at suggests only the session token is necessary.

  • Did you enable Session authentication under admin/structure/services/list/[my-endpoint] and clear all caches? Apr 16, 2015 at 15:23
  • Yes and yes. I don't think it would have worked in Postman if I hadn't enabled session authentication already. Apr 16, 2015 at 15:27
  • Ok, I only have experience in browser's where the cookie is taken care of automatically. So I think you need to also send along the session id in the header if you're making the call from a non JS environment (e.g. PHP). What code are you using to make the call? Apr 16, 2015 at 21:35
  • Entirely PHP. If I need to add the session id, do I add it to the Header? And what would be the key; Session/sessionid/session-id/etc? I've tried any combination I can think of with the same results. Apr 17, 2015 at 15:07

2 Answers 2


(Answering my own question, and trying to sound like a third-party so it makes better sense when read...)

It looks like it definitely has something to do with the session/cookie/etc., as subsequent calls seem to be coming from a different client (from the REST server's perspective.) I'm guessing bare PHP has no way of maintaining that cookie, like how a browser would. After looking here, it looks like the cookie needs to be formatted as such in the header of the request:

Cookie: session_name=sessid

(The cookie could also be retrieved from the response's headers->set_cookie variable. The latter will include all the expiration/link info in the string as well. While either method seems to work, I'm not sure if there are any ill-effects from one or the other. I just used the first method because it was the first solution I came across.)

Both session_name and sessid can be taken from the data area of the response after a user/login request. So the request would ultimately look something like this for a user/logout

POST /api/user/logout HTTP/1.0
Content-Type: application/json
Accept: application/json
X-CSRF-Token: igHUQD11Y8LYdyzHi8m5t33U_tCVZNHE6BbptE4mrwQ
Cookie: SESSd3a1acd26f95229c67cd0a9a1e455bd4=rv-Kbyb8znaGlYBBU5Dn7M2GzkYdWnun5aXcVYLVfvY
User-Agent: Drupal (+http://drupal.org/)
Host: mysiteurl.com
Content-Length: 0
  • I'm facing a similar problem, but I'm using Basic Auth for testing. I can create a node just fine (POST /entity/node...), but the subsequent edit requests (PATCH /node/123 or DELETE /node/123) fail with a 403. Basic Auth is enabled for content routes in the REST configuration.
    – aalaap
    Oct 27, 2017 at 7:24

Had this same problem before when trying to login in or get the X-CSRF-Token ( /services/session/token ) via api, it just changes the token every time upon refresh or upon request. My Solution is that to set withCredentials to true before post request. After I set it, page can now read the session cookie

Example xhr.withCredentials = true;

or in my case using Vue

Vue.http.interceptors.push((request, next) => {
    request.credentials = true;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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