Integrating Devise Invitable into Devise Token Auth

You might be familiar with Devise, a popular authentication solution that brings useful modules to your rails application, such as :confirmable, :recoverable, :registerable, :rememberable, among others. There is also the Devise Invitable gem that adds the :invitable extra module to it, allowing registered users to invite people to the system.

However, if your application has the only purpose to be an API, you might want to go with Devise Token Auth. It is a token base authentication designed to work with jToker and ng-token-auth, facilitating the integration of Devise with API clients. This gem is based on Devise, but overrides some original methods and controllers to adjust it for API purpose.

At the time this article was written, if you try to use the :invitable module with Devise Token Auth, it will raise an error. So, this post provides some details about the problem and explains how to solve it.

The Problem

When you try to use the :invitable module with Devise Token Auth you will face the following error:

ArgumentError in Devise::InvitationsController#create wrong number of arguments (1 for 0)

Devise Token Auth overrides the Devise controllers, but it is not expecting the InvitationsController included by Devise Invitable. The problem lies in the authenticate_user! method: while devise_token_auth does not expect any params, the original devise is expecting a hash.

  • more details can be found in this issue.

The Solution

In order to solve the above problem we need to override some methods in the InvitationsController to match the way Devise Token Auth works under the bonnet.


Let’s start telling devise_token_auth to not mount the routes for invitations. We need to mount it using the default devise_for, setting the controller that will override the original methods:

namespace :api do
mount_devise_token_auth_for 'User', at: 'auth', skip: [:invitations]
devise_for :users, path: "auth", only: [:invitations],
controllers: { invitations: 'api/invitations' }

Override Invitable Methods

In order to keep our code organised, we can create a new file in the controllers/concerns folder, called invitable_methods.rb. The following methods must be changed to match the way devise_token_auth works.

  • authenticate_user!: This method is raising the above error. We need to change it to match the method in devise_token_auth gem.
  • authenticate_inviter!: Originally it calls the authenticate_user!, but since we are changing it and replacing the controller, we can avoid this extra method.
  • resource_class(m = nil): Similar to authenticate_user!, we need to change it to match the devise_token_auth method.
  • resource_from_invitation_token: This method returns a flash message, but in our case we just need the json format.
module InvitableMethods
extend ActiveSupport::Concern

def authenticate_inviter!
# use authenticate_user! in before_action

def authenticate_user!
return if current_user
render json: {
errors: ['Authorized users only.']
}, status: :unauthorized

def resource_class(m = nil)
if m
mapping = Devise.mappings[m]
mapping = Devise.mappings[resource_name] || Devise.mappings.values.first

def resource_from_invitation_token
@user = User.find_by_invitation_token(params[:invitation_token], true)
return if params[:invitation_token] && @user
render json: { errors: ['Invalid token.'] }, status: :not_acceptable

Invitations Controller

We have successfully overridden all the methods that were incompatible with devise_token_auth, so we just need to create our InvitationsController and include the above InvitableMethods.

Our controller needs three actions:

  • create: Used to send the invitaton mail to an user. The authenticate_user! in a before_action ensures that only logged users can send an invitation. This action accepts the params defined in invite_params.
  • edit: When the invited user clicks on the link received by email, the resource_from_invitation_token will find and set the @user, and then render the edit action. Since there are no views to set the password in our Rails API, we need to redirect the user to the API client, sendding the invitation_token in the URL.
  • update: Finally, the update action will receive the accept_invitation_params, which includes the password, password_confirmation and the invitation_token sent to the API client. In case you want to update any other attribute, you can include it in the accept_invitation_params.
module Api
class InvitationsController < Devise::InvitationsController
include InvitableMethods
before_action :authenticate_user!, only: :create
before_action :resource_from_invitation_token, only: [:edit, :update]

def create
User.invite!(invite_params, current_user)
render json: { success: ['User created.'] }, status: :created

def edit
redirect_to "#{client_api_url}?invitation_token=#{params[:invitation_token]}"

def update
user = User.accept_invitation!(accept_invitation_params)
if @user.errors.empty?
render json: { success: ['User updated.'] }, status: :accepted
render json: { errors: user.errors.full_messages },
status: :unprocessable_entity


def invite_params
params.permit(user: [:email, :invitation_token, :provider, :skip_invitation])

def accept_invitation_params
params.permit(:password, :password_confirmation, :invitation_token)


At the time this article was written, the use of Devise Invitable with Devise Token Auth was not possible, since the :invitable module raised an error. This article discussed the problem and explained in details a workaround to solve the issue. After the above steps you should be able to successfully add the invitable feature to your Rails API.

Post by: Gabriel Hilal

Originally published at on November 7, 2015.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store