I'm using services 3.5 and I'm getting some troubles with rest server and session authentication.
I'm getting the "CSRF validation failed" error while trying to perform a create action on my resource.

My action should store data in a custom table in database and the create action requires authentication by default.
These are the steps I'm using to test (with curl in a ash script) my back end.

# Login saving cookies
curl -v -i -H "Content-type: application/json" -c cookies.txt -X POST -d '{"username":"myusername","password":"mypassword"}' "$login_url"

# Getting token
token="$(curl "$token_url")"

# Perform create action
curl -v -i -H "X-CSRF-Token: $token" -H "Content-type: application/json" -b cookies.txt -X POST -d '{"name":"myname", "surname":"mysurname", "email":"myemail"}' "$action_url"

I also tried with:
-H "X-CSRFToken: $token"

I found two different name for the CSRF Token header.

Two questions:
Is there a way to solve this problem?
Is there a way to avoid authentication for the action?

Thank you.

Comments

nimbuz77’s picture

Priority: Normal » Critical
James NBHD’s picture

I am having a similar problem.

I'm making two requests one to login/autheticate the user and a second to create a taxonomy term.

The User login CSRF is working correctly but I get a validation error on the taxonomy term create curl.

Both the CSRF calls are made using the function.

nimbuz77’s picture

I get a validation error on the taxonomy term create curl.

If you mean a data validation I think you pass the point I'm referring to.

I get a correct user authentication with the first call:
curl -v -i -H "Content-type: application/json" -c cookies.txt -X POST -d '{"username":"admin","password":"mypassword"}' http://localhost/[...]/endpoint/user/login

* Connection #0 to host localhost left intact
{"sessid":"a3F1dSJuD2wzekjOaRNsxUzpVhLDVfyETkAp_RRBtok","session_name":"SESSbbfa08561d1dfb8f8041451a3446e292","user":{"uid":"1","name":"admin","mail":"....","theme":"","signature":"","signature_format":null,"created":"1375260832","access":"1375440703","login":1375441971,"status":"1","timezone":"Europe/Berlin","language":"","picture":"0","init":"....","data":false,"roles":{"2":"authenticated user","3":"administrator"},"rdf_mapping":{"rdftype":["sioc:UserAccount"],"name":{"predicates":["foaf:name"]},"homepage":{"predicates":["foaf:page"],"type":"rel"}}}}* Closing connection #0

But the second call:
curl -v -i -H "X-CSRF-Token: $token" -H "Content-type: application/json" -b cookies.txt -X POST -d '{"name":"aname", "surname":"asurname", "email":"[email protected]"}' "http://localhost/[...]/endpoint/resource"

gives me the error:

* upload completely sent off: 70 out of 70 bytes
HTTP/1.1 401 Unauthorized: CSRF validation failed
...
Content-Type: application/json
...
 
* Connection #0 to host localhost left intact
["CSRF validation failed"]* Closing connection #0
marcingy’s picture

Priority: Critical » Normal

Support request are not critical

nimbuz77’s picture

Sorry for the wrong priority, I mean it is "critical" form my point of view :)
I'm completely stuck on this.

James NBHD’s picture

Not sure whether this will help - https://drupal.org/node/1334758#comment-7621035. It points out that

csrf token needs to be obtained in the same curl session as login

.

It worked for me.

nimbuz77’s picture

You mean by attaching the session cookie to the token request?

nimbuz77’s picture

Yes, I mean that.
It worked for me also

derekwebb1’s picture

For me I created a getToken function in my little ajax helper script:

  Drupal.ajaxHelper.getToken = function(success, error) {
  	$.ajax({
  		url:'/services/session/token',
  		dataType: 'text',
  		success: success,
  		error: error
  	});
  };

Then, in the node create side:

  Drupal.ajaxHelper.create = function(type, entity, success, error) {
		var obj = {}; // the entity to be saved
		obj[type] = entity;

		this.getToken( // CSRF token validation now required
			function(data, msg, xhr) {
				token = data; // data loaded ok
				$.ajax({
		      url:'/system/'+type+'.json',
		      type: "POST",
					beforeSend: function(xhr) { xhr.setRequestHeader('X-CSRF-Token', token); },
					data: JSON.stringify(obj),
					contentType: 'application/json',
					dataType: 'json',      
					success: success,
					error: error
		    });
			},
			function (jqXHR, status, err) {
        console.log('CSRF token not retrieved! '+err);
			}
		);
  };

This solves the issue for me. I hope it helps someone.

Cheers

kylebrowning’s picture

Issue summary: View changes
Status: Active » Closed (fixed)
hmuthukumar’s picture

Thanks @derekwebb1 your solution getting the token and passing as X-CSRF-Token for future calls #9 worked for me

Also to solve the original issue posted in the question you may need to set the cookie for the gettoken curl call.