Skip to content

Initial Devise sign in

Gonzalo Bulnes Guilpain edited this page Jan 2, 2021 · 10 revisions

Simple Token Authentication only provides the functionality to authenticate a user based on their authentication_token.

When used to authenticate API clients (e.g. a front-end or mobile app), the client is responsible for retrieving the authentication token in the first place. Typically that is done using another Devise strategy for sign in (e.g. database authentication where users provide their email and password).

This How-to explains how to modify Devise JSON response to a successful sign in so that it includes the current user authentication token.

Note that once that the authentication token is stored in the API client, users don't need to provide their password again until the token is renewed (server-side).

Server-side

The following example (based on Devise::SessionsController v4.1) is one possible approach to return the current user's authentication token after a successful sign in:

# app/controllers/users/sessions_controller.rb

class Users::SessionsController < Devise::SessionsController

  def create
    respond_to do |format|
       format.any(*navigational_formats) { super }
       format.json do
         self.resource = warden.authenticate!(auth_options)
         sign_in(resource_name, resource)
         respond_with_authentication_token(resource)
       end
    end
  end

  protected

  def respond_with_authentication_token(resource)
    render json: {
      success: true,
      auth_token: resource.authentication_token,
      email: resource.email
    }
  end

end

Thanks @jeremylynch!

Changing the routes to match the new updated Sessions Controller

# routes.rb file:

 devise_for :users, only: [:sessions], controllers: {sessions: 'users/sessions'}

Using full Rails

InvalidAuthenticityToken error

You can solve the error ActionController::InvalidAuthenticityToken in Users::SessionsController#create by adding the following to your Applicationcontroller:

  # app/controllers/application_controller.rb

  protect_from_forgery with: :null_session, if: :json_request?

  protected

  def json_request?
    request.format.json?
  end

Testing request with cURL

curl --request POST \
  --url http://localhost:3000/users/sign_in \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
	"user": {
		"email":"[email protected]",
		"password":"password"
	}
}'

Client-side

Have you implemented token authentication in a mobile app or a front-end component? Contributed examples would be welcome!