How do I authenticate using Devise in a Rails REST API App?
After getting a few tips, I found a number of great sites. There are several ways to do this, however I don't know which one is best, but these sites help a long way:
- https://github.com/lynndylanhurley/devise_token_auth (An extension to
Devise) - https://labs.kollegorna.se/blog/2015/04/build-an-api-now/
(Manual way) - Token based authentication for Rails JSON APIs (SO Question)
- Rails API : Best way to implement authentication? (SO Question)
- Rails API : Best way to implement authentication?
How to pass authentication token in RSpec test for JSON API?
Use it like:
get '/api/v1/projects/1', {}, { Authorization: "Token 123"}
get
is the http method, {}
an empty params, { :Authorization => "Token 123"}
headers
get(path, parameters = nil, headers_or_env = nil)
Documentation
Other way:
before do
# some code here
@request.env['Authorization'] = "Token 123"
get '/api/v1/projects/1', format: :json
end
Rails API : Best way to implement authentication?
The important point, from a security perspective, is to exchange the user's email and password for a token once, and then use that token for subsequent requests. This is because:
- You don't want the client app to be responsible for holding onto the user's password, where a bug or attack could cause it to be leaked; and
- A server-issued token gives you (and your users) the ability to expire a token if necessary, e.g. to lock out a stolen device or block a misbehaving API client.
There are many ways to accomplish this with varying levels of complexity.
Here is a tutorial that is very recent and has a thorough walkthrough for creating an API in Rails with token-based authentication (not using Devise, but still relevant to understand the concepts): https://labs.kollegorna.se/blog/2015/04/build-an-api-now/
Rails REST API Server: protect_from_forgery option and where to put authentication token
If you don't use cookies to authorize your client, CSRF can't be accomplished. It works only because browser would automatically add cookie to the request. E.g. when you open the following picture:
<img src="my.bank/withdraw_funds?to=john_doe">
you browser will make request to my.bank
with cookies attached, authorizing the transfer.
But if you use some API token (as a request parameter or as a header), there is no way to make a malicious image/form that will add that token to the request (because the attacker doesn't know a token).
And, yes, you should put this token into the database. Rails' session
use cookies, and API server, as mentioned, shouldn't rely on them.
You authentication method (probably somewhere in ApplicationController
) would look like this:
before_action :authenticate
def authenticate
@user = User.where(token: params.require(:token)).first
end
And then you can use @user
in your actions. On the client side you just add ?token=...
to your request parameters.
If you use headers (and it's better, at least because you shouldn't worry about token being saved in proxy servers' logs when you do GET requests), you add X-Authentication-Token: ...
header to your request, and then modify your ApplicationController
like that:
before_action :authenticate
def authenticate
@user = User.where(token: request.headers['HTTP_X_AUTHENTICATION_TOKEN']).first
end
Related Topics
"Rmagick" Gem Installation Issue
Rails Routing (Root :To => ...)
How to Force Ruby to Show a Full Stack Trace
Find Records with Datetime That Match Today's Date - Ruby on Rails
What Alternatives to Irb Are There
Ruby Methods That Either Yield or Return Enumerator
Ruby on Rails, Two Models in One Form
Reading the First Line of a File in Ruby
Rails - How to Check Developer Mode or Production Mode in Code
How to Return Multiple Tags from a Rails Helper
Unit Test in Rails - Model with Paperclip