Ruby on rails
is still the frontrunner for getting an MVP(minimum viable product) out of the door. Eventual when things go our way we want to introduce F/E framework on the customer facing side for various reasons(continue using the admin part as traditional rails app). If you are already using devise
and wondering how to use it for api
calls this post is for you.
The devise_token_auth
is a gem on top of devise
which works with tokens and leverages on devise
. We can even configure it to either refresh the token for every single request or not.
Without further delay let’s jump in.
Add the following to your Gemfile
. We need rack-cors
to get support for Cross-Origin Resource Sharing (CORS).
gem ‘devise_token_auth’
gem ‘rack-cors‘
Then install the gem using bundle:
bundle install
Assuming we are using User
model run the following command to prepare for the setup.
rails g devise_token_auth:install User auth
This is going to generate the following files
create config/initializers/devise_token_auth.rb
insert app/controllers/application_controller.rb
gsub config/routes.rb
create db/migrate/20190712184641_devise_token_auth_create_users.rb
insert app/models/user.rb
So far we have done exactly as mentioned in the docs which thinks there is no devise
functionality already implemented.
As we want new token implementation to work on top of our existing admin side(traditional rails app using devise
) do the following changes.
routes.rb
: Move mount_devise_token_auth_for User, at: auth
into api
routes. As we only want this routes to be used in the context of api
.
mount_devise_token_auth_for 'User', at: 'auth'
namespace :api do
namespace :v1 do
mount_devise_token_auth_for 'User', at: 'auth', defaults: {format: 'json'}
application_controller.rb
: Remove include DeviseTokenAuth::Concerns::SetUserByToken
from application_controller.rb
and move to your api base controller. Else this will mess up with your devise
authentication.
class Api::V1::BaseController
include DeviseTokenAuth::Concerns::SetUserByToken
- Rename migration to
xxx_devise_token_auth_update_users
and make sure you remove all the existing devise module columns which you already have.
class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[5.2] def change change_table(:users) do |t| ## Required t.string :provider, :null => false, :default => "email"
t.string :uid, :null => false, :default => ""
t.boolean :allow_password_change, default: true
## Tokens
t.json :tokens
end
end
end
User.rb
: Remove the modules you already included. I don’t need omniauth
at this moment so i removed it.
# Include default devise modules.
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable
include DeviseTokenAuth::Concerns::User
Apart from the above i made the following changes to make it work.
class Api::V1::BaseController < JSONAPI::ResourceController
include DeviseTokenAuth::Concerns::SetUserByToken
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_in, keys: [:email, :password])
end
In application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
protect_from_forgery with: :null_session, if: -> { request.format.json? }
wrap_parameters false
In development.rb
resource '*', headers: :any,
expose: %w(etag access-token uid expiry token-type client Rate-Search-Uuid),
methods: [:get, :post, :delete, :put, :patch, :options, :head]
Now you can send a curl command like below.
curl -X POST http://localhost:3000/api/v1/auth/sign_in
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'cache-control: no-cache' \
-H 'content-type: multipart/form-data;
-F email=email@company.com \
-F password=password
The success response consists of access_token
, uid
, client
from headers. Don’t forget to send these back and forth on the consecutive requests.
Drop comments if you are stuck or have any concerns.
Thanks!