You don’t want to disable CSRF, I have read that people think it doesn’t apply to JSON APIs for some reason, but this is a misunderstanding. To keep it enabled, you want to make a few changes:
-
on there server side add a after_filter to your sessions controller:
after_filter :set_csrf_header, only: [:new, :create] protected def set_csrf_header response.headers['X-CSRF-Token'] = form_authenticity_token endThis will generate a token, put it in your session and copy it in the response header for selected actions.
-
client side (iOS) you need to make sure two things are in place.
-
your client needs to scan all server responses for this header and retain it when it is passed along.
... get ahold of response object // response may be a NSURLResponse object, so convert: NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; // grab token if present, make sure you have a config object to store it in NSString *token = [[httpResponse allHeaderFields] objectForKey:@"X-CSRF-Token"]; if (token) [yourConfig setCsrfToken:token]; -
finally, your client needs to add this token to all ‘non GET’ requests it sends out:
... get ahold of your request object if (yourConfig.csrfToken && ![request.httpMethod isEqualToString:@"GET"]) [request setValue:yourConfig.csrfToken forHTTPHeaderField:@"X-CSRF-Token"];
-
Final piece of the puzzle is to understand that when logging in to devise, two subsequent sessions/csrf tokens are being used. A login flow would look like this:
GET /users/sign_in ->
// new action is called, initial token is set
// now send login form on callback:
POST /users/sign_in <username, password> ->
// create action called, token is reset
// when login is successful, session and token are replaced
// and you can send authenticated requests