Any modern Rails web app will need an API to power mobile and/or desktop clients, and maybe even a SPA later on. The devise_token_auth gem adds API user authentication to our app with minimum effort and total configurability. Here's a quick guide on how to set it up, together with solutions to the gotchas that come with it.
We start on our
Gemfile, as usual:gem 'devise' gem 'devise_token_auth' # Token based authentication for Rails JSON APIs gem 'omniauth' # required for devise_token_auth
Now, let's generate the User model that will use token authentication. "User" is our model's name, while "auth" is the path where our authentication endpoints will be mounted.
rails g devise_token_auth:install User authThis command will give us the following:
-
A user model with the proper devise modules for authentication, registration and so on, including the
DeviseTokenAuthmodule for API authentication:
class User < ActiveRecord::Base devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :omniauthable include DeviseTokenAuth::Concerns::User end -
A migration to setup the model:
class DeviseTokenAuthCreateUsers < ActiveRecord::Migration def change create_table(:users) do |t| ## Required t.string :provider, :null => false t.string :uid, :null => false, :default => "" ## Database authenticatable t.string :encrypted_password, :null => false, :default => "" # ... ## User Info t.string :name t.string :nickname t.string :image t.string :email ## Tokens t.text :tokens t.timestamps end add_index :restaurant_users, :email # ... end end -
The routes for our auth endpoint (I namespaced them to add versioning for the API):
namespace :api do scope :v1 do mount_devise_token_auth_for "User", at: 'auth' end end
- A user that uses
DeviseTokenAuthcan also be authenticated with normal Devise, but the Devise routes must come first. More info here.
-
Rails comes with CSRF prevention by raising an exception. This will make your token auth fail when accessed via the API. To fix it, change it on your
app/controllers/application_controller.rb:
class ApplicationController < ActionController::Base protect_from_forgery with: :null_session # ... end -
This gem comes with a sturdy security default configuration. Unless you're using the ng-token-auth lib for authentication on Angular, I suggest to disable the
change_headers_on_each_requesoption on the gem's config (config/initializers/devise_token_auth.rb), to ease development.
| path | method | purpose |
|---|---|---|
| / | POST | Email registration. Accepts email, password, and password_confirmation params. |
| / | DELETE | Account deletion. This route destroys users identified by their uid and auth_token headers. |
| / | PUT | Account updates. This route updates an existing user's account settings. The default accepted params are password and password_confirmation.
|
| /sign_in | POST | Email authentication. Accepts email and password as params. Return a JSON representation of the User model on successful login. |
| /sign_out | DELETE | Use this route to end the user's current session, by invalidating their authentication token. |
| /validate_token | GET | Use this route to validate tokens on return visits to the client. Accepts uid and auth_token as params.
|
| /password | POST | Use this route to send a password reset confirmation email to users that registered by email. |
| /password | PUT | Use this route to change users' passwords. |
| /password/edit | GET | Verify user by password reset token. This route is the destination URL for password reset confirmation. |
Have you tried any other token-based solution for API authentication, or built one yourself? Having problems implementing this one on your app? Share it on the comments!

Fantastic post, very informative. I wonder why the other specialists of this sector do not notice this. You must continue your writing. I'm confident, you have a great readers' base already!
ReplyDeleteSocial Network Web Development