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
DeviseTokenAuth
module 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
DeviseTokenAuth
can 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_reques
option 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