Skip to content

Configuring devise for APIs

Marc Busqué edited this page Feb 2, 2023 · 4 revisions

Controllers

Responding to json

In order for devise to know it can respond to json format, you need to instruct the controller layer. Usually, you will add the following in ApplicationController:

respond_to :json

If you are inheriting from ActionController::API, first you will need to bring that functionality back:

include ActionController::MimeResponds

Overriding controllers

Overriding devise controllers should be the last option to consider. However, if this is necessary, some devise actions yield the user in the crucial moment so that an override can call super and just perform the needed action with it.

For example, if you need to override SessionsController just to assign the user as an instance variable for the view, it is enough to do:

class MyApplicationSessionsController < Devise::SessionsController
  def create
    super { |resource| @resource = resource }
  end
end

Then, don't forget in your routes:

devise_for :users, controllers: { sessions: 'my_application_sessions' }

Routes

Defaulting to json as format

If you want devise routes to use json as default format (that is, you don't need to add .json at the end of the URLs), use defaults as the following:

devise_for :users, defaults: { format: :json }

Views

Validation errors format

Devise uses responders. In order to adjust validation errors coming from devise (for instance, during a sign up) to our application standards, we need to define and use a responder, which will need to implement the json_resource_errors method. As it is included in the general responder, it has access to a resource instance variable which in our case will contain the user with its errors. For instance:

module MyApplicationResponder
  protected

  def json_resource_errors
    {
      success: false,
      errors: MyApplicationErrorFormatter.call(resource.errors)
    }
  end
end

Then, in the controller you have to use it:

responders :my_application

Authentication errors format

When an authentication fails, the execution path exits our application and lands into the default devise failure application. It is responsible to render the error message.

If we want to render with our own errors format standard, we should define and use a custom failure application. It is sufficient to just inherit from the devise one and overwrite the http_auth_body method. From there, i18n_message contains the error message.

For example:

class MyApplicationFailureApp < Devise::FailureApp
  def http_auth_body
    return super unless request_format == :json
    {
      sucess: false,
      message: i18n_message
    }.to_json
  end
end

Now, in config/initializers/devise.rb we need to config Warden (the engine on top of devise) to use it:

config.warden do |manager|
  manager.failure_app = MyApplicationFailureApp
end