Token Based Authentication for Rails JSON APIs

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:

  1. 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
  2. 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



Leave a reply



Submit