read
In previous post we saw how to buil RESTful API using Grape. In this post we will see how to add devise auth token to users and how to use it in Grape API authentication.
Lets see how this can be done assuming you already have devise setup ready.
## Add token_authenticable to devise modules (works with devise versions <=3.2)
In user.rb add :token_authenticatable to the list of devise modules, it should look something like below:
<div class='code-highlight'><pre class='code-highlight-pre'><div data-line='1' class='code-highlight-row numbered'><div class='code-highlight-line'>class User < ActiveRecord :: Base
</div></div><div data-line='2' class='code-highlight-row numbered'><div class='code-highlight-line'># ..code..
</div></div><div data-line='3' class='code-highlight-row numbered'><div class='code-highlight-line'> devise :database_authenticatable ,
</div></div><div data-line='4' class='code-highlight-row numbered'><div class='code-highlight-line'> :token_authenticatable ,
</div></div><div data-line='5' class='code-highlight-row numbered'><div class='code-highlight-line'> :invitable ,
</div></div><div data-line='6' class='code-highlight-row numbered'><div class='code-highlight-line'> :registerable ,
</div></div><div data-line='7' class='code-highlight-row numbered'><div class='code-highlight-line'> :recoverable ,
</div></div><div data-line='8' class='code-highlight-row numbered'><div class='code-highlight-line'> :rememberable ,
</div></div><div data-line='9' class='code-highlight-row numbered'><div class='code-highlight-line'> :trackable ,
</div></div><div data-line='10' class='code-highlight-row numbered'><div class='code-highlight-line'> :validatable
</div></div><div data-line='11' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='12' class='code-highlight-row numbered'><div class='code-highlight-line'> attr_accessible :name , :email , :authentication_token
</div></div><div data-line='13' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='14' class='code-highlight-row numbered'><div class='code-highlight-line'> before_save :ensure_authentication_token
</div></div><div data-line='15' class='code-highlight-row numbered'><div class='code-highlight-line'># ..code..
</div></div><div data-line='16' class='code-highlight-row numbered'><div class='code-highlight-line'>end </div></div></pre></div>
## Generate Authentication token on your own (If devise version > 3.2)
<div class='code-highlight'><pre class='code-highlight-pre'><div data-line='1' class='code-highlight-row numbered'><div class='code-highlight-line'>class User < ActiveRecord::Base
</div></div><div data-line='2' class='code-highlight-row numbered'><div class='code-highlight-line'># ..code..
</div></div><div data-line='3' class='code-highlight-row numbered'><div class='code-highlight-line'> devise :database_authenticatable,
</div></div><div data-line='4' class='code-highlight-row numbered'><div class='code-highlight-line'> :invitable,
</div></div><div data-line='5' class='code-highlight-row numbered'><div class='code-highlight-line'> :registerable,
</div></div><div data-line='6' class='code-highlight-row numbered'><div class='code-highlight-line'> :recoverable,
</div></div><div data-line='7' class='code-highlight-row numbered'><div class='code-highlight-line'> :rememberable,
</div></div><div data-line='8' class='code-highlight-row numbered'><div class='code-highlight-line'> :trackable,
</div></div><div data-line='9' class='code-highlight-row numbered'><div class='code-highlight-line'> :validatable
</div></div><div data-line='10' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='11' class='code-highlight-row numbered'><div class='code-highlight-line'> attr_accessible :name, :email, :authentication_token
</div></div><div data-line='12' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='13' class='code-highlight-row numbered'><div class='code-highlight-line'> before_save :ensure_authentication_token
</div></div><div data-line='14' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='15' class='code-highlight-row numbered'><div class='code-highlight-line'> def ensure_authentication_token
</div></div><div data-line='16' class='code-highlight-row numbered'><div class='code-highlight-line'> self.authentication_token ||= generate_authentication_token
</div></div><div data-line='17' class='code-highlight-row numbered'><div class='code-highlight-line'> end
</div></div><div data-line='18' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='19' class='code-highlight-row numbered'><div class='code-highlight-line'> private
</div></div><div data-line='20' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='21' class='code-highlight-row numbered'><div class='code-highlight-line'> def generate_authentication_token
</div></div><div data-line='22' class='code-highlight-row numbered'><div class='code-highlight-line'> loop do
</div></div><div data-line='23' class='code-highlight-row numbered'><div class='code-highlight-line'> token = Devise.friendly_token
</div></div><div data-line='24' class='code-highlight-row numbered'><div class='code-highlight-line'> break token unless User.where(authentication_token: token).first
</div></div><div data-line='25' class='code-highlight-row numbered'><div class='code-highlight-line'> end
</div></div><div data-line='26' class='code-highlight-row numbered'><div class='code-highlight-line'> end</div></div></pre></div>
Add migration for authentiction token
rails g migration add_auth_token_to_users
create db/migrate/20140326204628_add_auth_token_to_users.rb
Edit migration file to add :authentication_token
column to users
<div class='code-highlight'><pre class='code-highlight-pre'><div data-line='1' class='code-highlight-row numbered'><div class='code-highlight-line'># db/migrate/20140326204628_add_auth_token_to_users.rb
</div></div><div data-line='2' class='code-highlight-row numbered'><div class='code-highlight-line'>class AddAuthTokenToUsers < ActiveRecord::Migration
</div></div><div data-line='3' class='code-highlight-row numbered'><div class='code-highlight-line'> def self.up
</div></div><div data-line='4' class='code-highlight-row numbered'><div class='code-highlight-line'> change_table :users do |t|
</div></div><div data-line='5' class='code-highlight-row numbered'><div class='code-highlight-line'> t.string :authentication_token
</div></div><div data-line='6' class='code-highlight-row numbered'><div class='code-highlight-line'> end
</div></div><div data-line='7' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='8' class='code-highlight-row numbered'><div class='code-highlight-line'> add_index :users, :authentication_token, :unique => true
</div></div><div data-line='9' class='code-highlight-row numbered'><div class='code-highlight-line'> end
</div></div><div data-line='10' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='11' class='code-highlight-row numbered'><div class='code-highlight-line'> def self.down
</div></div><div data-line='12' class='code-highlight-row numbered'><div class='code-highlight-line'> remove_column :users, :authentication_token
</div></div><div data-line='13' class='code-highlight-row numbered'><div class='code-highlight-line'> end
</div></div><div data-line='14' class='code-highlight-row numbered'><div class='code-highlight-line'>end</div></div></pre></div>
Run migrations
Generate token for existing users
We need to call save on every instance of user that will ensure authentication token is present for each user.
<div class='code-highlight'><pre class='code-highlight-pre'><div data-line='1' class='code-highlight-row numbered'><div class='code-highlight-line'>User.all.each(&:save)</div></div></pre></div>
Secure Grape API using auth token
You need to add below code to the API::Root in-order to add token based authentication. If you are unware of API::Root then please read Building RESTful API using Grape
In below example, We are authenticating user based on two scenarios
- If user is logged on to the web app then use the same session
- If session is not available and auth token is passed then find user based on the token
<div class='code-highlight'><pre class='code-highlight-pre'><div data-line='1' class='code-highlight-row numbered'><div class='code-highlight-line'># lib/api/root.rb
</div></div><div data-line='2' class='code-highlight-row numbered'><div class='code-highlight-line'>module API
</div></div><div data-line='3' class='code-highlight-row numbered'><div class='code-highlight-line'> class Root < Grape :: API
</div></div><div data-line='4' class='code-highlight-row numbered'><div class='code-highlight-line'> prefix 'api'
</div></div><div data-line='5' class='code-highlight-row numbered'><div class='code-highlight-line'> format :json
</div></div><div data-line='6' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='7' class='code-highlight-row numbered'><div class='code-highlight-line'> rescue_from :all , :backtrace => true
</div></div><div data-line='8' class='code-highlight-row numbered'><div class='code-highlight-line'> error_formatter :json , API :: ErrorFormatter
</div></div><div data-line='9' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='10' class='code-highlight-row numbered'><div class='code-highlight-line'> before do
</div></div><div data-line='11' class='code-highlight-row numbered'><div class='code-highlight-line'> error! ( "401 Unauthorized" , 401 ) unless authenticated
</div></div><div data-line='12' class='code-highlight-row numbered'><div class='code-highlight-line'> end
</div></div><div data-line='13' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='14' class='code-highlight-row numbered'><div class='code-highlight-line'> helpers do
</div></div><div data-line='15' class='code-highlight-row numbered'><div class='code-highlight-line'> def warden
</div></div><div data-line='16' class='code-highlight-row numbered'><div class='code-highlight-line'> env [ 'warden' ]
</div></div><div data-line='17' class='code-highlight-row numbered'><div class='code-highlight-line'> end
</div></div><div data-line='18' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='19' class='code-highlight-row numbered'><div class='code-highlight-line'> def authenticated
</div></div><div data-line='20' class='code-highlight-row numbered'><div class='code-highlight-line'> return true if warden . authenticated?
</div></div><div data-line='21' class='code-highlight-row numbered'><div class='code-highlight-line'> params [ :access_token ] && @user = User . find_by_authentication_token ( params [ :access_token ] )
</div></div><div data-line='22' class='code-highlight-row numbered'><div class='code-highlight-line'> end
</div></div><div data-line='23' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='24' class='code-highlight-row numbered'><div class='code-highlight-line'> def current_user
</div></div><div data-line='25' class='code-highlight-row numbered'><div class='code-highlight-line'> warden . user || @user
</div></div><div data-line='26' class='code-highlight-row numbered'><div class='code-highlight-line'> end
</div></div><div data-line='27' class='code-highlight-row numbered'><div class='code-highlight-line'> end
</div></div><div data-line='28' class='code-highlight-row numbered'><div class='code-highlight-line'> </div></div><div data-line='29' class='code-highlight-row numbered'><div class='code-highlight-line'> mount API :: V1 :: Root
</div></div><div data-line='30' class='code-highlight-row numbered'><div class='code-highlight-line'> mount API :: V2 :: Root
</div></div><div data-line='31' class='code-highlight-row numbered'><div class='code-highlight-line'> end
</div></div><div data-line='32' class='code-highlight-row numbered'><div class='code-highlight-line'>end </div></div></pre></div>