I've been developing Rails app with REST API for access from mobile application.
It works quite well. When user logs in from mobile application, he gets auth_token
that he uses in his future requests to API. The issue is that API is also accessible from web by going to path /api/v1/... and because of this, it has to be protected from CSRF.
I have BaseApiController
class which inherits from ApplicationController
that has protect_from_forgery
"enabled". Here's example:
class Api::V1::BaseApiController < ApplicationController
# ...
end
class ApplicationController < ActionController::Base
protect_from_forgery
# ...
end
Now, when I do non-GET requests to my API, with auth_token
, my request gets completed successfully, but in the logs I can see the famous WARNING: Can't verify CSRF token authenticity
. If I remove protect_from_forgery
from my BaseApiController
, I don't get any warnings (obviously), but then my API is vulnerable to CSRF attacks (I made a simple HTML form that successfully changes the data across domains when there's no protect_from_forgery
).
My question is: How to assure my API stays secure, but also remove the warning when doing non-GET requests?
Here's one of the solutions I've come up with, but it looks more like a hack and executes one extra DB query:
class Api::V1::BaseApiController < ApplicationController
# ...
def verified_request?
super || User.where(authentication_token: params['auth_token']).count > 0
end
end
More details about the project: Rails 3.2.14, Devise, AngularJS. The project's source code can be found here.