Guide to devise_token_auth: Simple Authentication in Rails API
Tags: rails, ruby, devisetokenauth, authentication
Published: 2019-02-09 10:05:47

---
title: Guide to devise_token_auth: Simple Authentication in Rails API
published: true
description: 
tags: rails, ruby, devise_token_auth, authentication
---

I wanted to create an authentication system for my Rails API, but one thing about APIs (with no client) is that you can't use sessions or cookies for authentication.
So instead, I used the gem [`devise_token_auth`](https://github.com/lynndylanhurley/devise_token_auth), which uses tokens. Put simply, this is how it works: when you make HTTP requests to sign up or log in, the response headers give you authentication tokens, which you send in subsequent HTTP requests' headers to prove that you're authenticated.

While the [official docs](https://devise-token-auth.gitbook.io/devise-token-auth/) provide most of the information you need, there were a few points that I found confusing so I'm leaving this article for future reference. Hope it helps! 

Note: Guide is for Linux or MacOS.

# Implementation Steps
Please also feel free to check out the bare-bones [repository](https://github.com/risafj/demo-for-devise-token-auth) I created, as a proof of concept for how to use this gem. 

## 1. Install devise_token_auth
Add the following to your `Gemfile`, then run `bundle` from your command line:
```ruby
gem 'devise_token_auth'
```

## 2. Generate necessary files
Execute this from your command line.

```
rails g devise_token_auth:install User auth
```
This will do many things, including:
- Create a `User` model, which stores information such as users' email addresses, and a corresponding migration file
- Add a line in your `config/routes.rb` file specifying the route for authentication endpoints like sign up or sign in (If you want it routed somewhere other than `/auth/`, swap out the "`auth`" in the command with something else)

For the exhaustive list of what this command does, check out the [docs](https://devise-token-auth.gitbook.io/devise-token-auth/config).

### Update
According to Rafael's comment below, it's now necessary to add `extend Devise::Models` to the `User` model file generated here. Details can be found in this Github [issue](https://github.com/lynndylanhurley/devise_token_auth/issues/1276#issuecomment-478866479).
{% devcomment h2ig %}

## 3. Migrate your database
Run `rails db:migrate` in your command line to apply the migration file that was created in step #2, which probably looks something like `db/migrate/YYYYMMDDTTTT_devise_token_auth_create_users.rb`. 

## 4. Configure your initializer file
Go to your `config/initializers/devise_token_auth.rb` file (also created in the `rails g` command in step #2).

Again, the [docs](https://devise-token-auth.gitbook.io/devise-token-auth/config/initialization) have the complete list of configurations you can make, but to give an example:
```ruby
config.change_headers_on_each_request = false
```
By default, the authorization headers change with each request. This means that you would get back new tokens with each request, and you would have to send back different tokens each time. I wanted to be able to keep using the same tokens, so I turned it off by setting it to `false`.
Reusing your tokens is not the best security practice, so it may be better to use fresh tokens each time in production.

## 5. Disable forgery protection for JSON requests
Rails controllers have pre-set measures against Cross-Site Request Forgery (CSRF) attacks. This involves comparing tokens in the rendered HTML to tokens that Rails stores automatically in your session, but for APIs, we have no sessions and will use our own tokens so it's unnecessary (explained [here](https://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html)).

> It's important to remember that XML or JSON requests are also affected and if you're building an API you should change forgery protection method in ApplicationController (by default: :exception)

So go ahead and disable forgery check for JSON format requests, in `app/controllers/application_controller.rb`.
Note: Only do this if all your requests come in through your API.

```ruby
class ApplicationController < ActionController::Base
  protect_from_forgery unless: -> { request.format.json? }
end
```

### Notes/Caveats
* Skipping this step should result in this error: `ActionController::InvalidAuthenticityToken in DeviseTokenAuth::RegistrationsController#create`.
* If your `ApplicationController` inherits from `ActionController::API` (which should be the case if you initialized the project with the `--api` flag), this step should be unnecessary as there is no forgery protection by default.

## 6. Try signing up a user
Now, let's try signing up a test user. Boot up your Rails server from the command line with `rails s`, and send a HTTP POST request to `localhost:3000/auth/` (or your custom route) with the following parameters.

```
{
  "email": "test@email.com",
  "password": "password",
  "password_confirmation": "password"
}
```

It should return status 200 - success. Now your authentication system works!

## 7. Add authentication to your controller
Next, add a line in the respective controller file to make authentication necessary. For example, let's say we're building an API for a database that stores information on books. We have the file `books_controller.rb` for adding or deleting books from the database. We want to authenticate the user _before_ they add or delete entries.

```ruby
class BooksController < ApiController
  before_action :authenticate_user!

  # Code for methods such as create and delete should come here.
end
```
Now, any time you send a HTTP request to any methods in your books controller, an error will be returned unless you're authenticated.

# Actual Usage
I mentioned earlier that the HTTP request for signing up users is a POST request to `localhost:3000/auth/`. As for the full list of methods (e.g. logging users in/out, and changing their passwords), please refer to the [docs](https://devise-token-auth.gitbook.io/devise-token-auth/usage). You can see what request type, route, and parameters are required.

Finally, let's talk about actual usage. Here are the steps involved:

1. Send authentication request (sign up or sign in)
2. Status 200 is returned, with valid authentication tokens in the headers
3. In your next request, send those tokens in your headers

The required token categories are:
- access-token
- client
- uid

It's that simple!

I wanted to also discuss tips for testing, but since this is getting long, I will write that in a separate post. Thanks for reading :)

### Update
Here is the article on testing!
{% link https://dev.to/risafj/tips-for-testing-authentication-with-devisetokenauth-in-rails-api-55pj %}

### Additional Update
It seems like the `trackable` module was dropped from the `devise` gem, which `devise_token_auth` is based on. So the default configuration in the `User` model, which includes `:trackable`, is likely to raise an error like this: `NoMethodError: undefined method 'current_sign_in_at'`. 
For details on how to resolve this, see the links below:
* https://stackoverflow.com/questions/55735895/nomethoderror-undefined-method-current-sign-in-at-for-user0x000055ce01dcf0a
* https://www.bountysource.com/issues/75245078-cant-log-in-nomethoderror-undefined-method-current_sign_in_at-for-user-0x000055e053c79c58