Tips for testing: Authentication with devise_token_auth in Rails API
Tags: ruby, rails, testing, authentication
Published: 2019-03-24 06:58:27

---
title: Tips for testing: Authentication with devise_token_auth in Rails API
published: true
description: 
tags: ruby, rails, testing, authentication
---

Previously, I wrote a blog post on how to create an authentication system for Rails API with the `devise_token_auth` gem.
{% link https://dev.to/risafj/guide-to-devisetokenauth-simple-authentication-in-rails-api-pfj %}

But to be honest, the most unintuitive part for me was not adding the authentication system itself, but testing it and any functions that use it. So this post focuses on testing, more specifically:
1. How do you write tests for the authentication system?
2. How do you write controller tests for functions that require authentication?

The first point is self-explanatory. As for the second: let's say you're creating an application for library books. You can add new books to the database with an HTTP POST request to `/books`, but you need to be authenticated to do this. If no authentication was involved, you could test the method for adding books like below, but this test would fail in our case because the request is not authenticated.

```ruby
# test/controllers/books_controller_test.rb
test 'should create new book' do
  post 'books/',
    params: {
    name: 'Harry Potter'
    }
  assert_response :success
end
```

Note: Guide is for Linux or MacOS systems, and uses minitest for testing.



# Overview #
Here are the steps involved.
- Write helper authorization methods that we’ll use in our tests in `test/helpers/authorization_helper.rb`
- Create `test/authorization_test.rb` for testing our authorization helper code
- In the tests for methods that require authentication, call the authorization methods in `authorization_helper.rb`

# Step 1. Create authorization helper file #
One solution to the problem I described above (tests failing for unauthenticated requests) is to add one step for login to the first part of each test for methods that require authentication. But this would result in a lot of redundant code. A better way to handle this is to make a helper file with the necessary authentication methods, and call those methods in your controller tests.

In `test/helpers`, create a file called `authorization_helper.rb`. Inside, write the methods you'll use in your tests, like signing in and getting the authentication tokens from the headers (demonstrated below).

```ruby
module AuthorizationHelper
  def sign_up(user)
    # The argument 'user' should be a hash that includes the params 'email' and 'password'.
    post '/auth/',
      params: { email: user[:email],
                password: user[:password],
                password_confirmation: user[:password] },
      as: :json
  end

  def auth_tokens_for_user(user)
    # The argument 'user' should be a hash that includes the params 'email' and 'password'.
    post '/auth/sign_in/',
      params: { email: user[:email], password: user[:password] },
      as: :json
    # The three categories below are the ones you need as authentication headers.
    response.headers.slice('client', 'access-token', 'uid')
  end
end
```

Bear in mind that this code cannot be run as-is, since this is meant to be called inside tests.

# Step 2. Test your authorization helper code #
In your `test` folder, create a file called `authorization_test.rb`. Then, you can test the methods in your helper file.

For example:
```ruby
test 'sign up and log in user one' do
    user_one = { email: 'userone@test.com', password: 'password' }
    sign_up(user_one)
    assert_response :success

    (user_one)
    assert_response :success
  end
```
Now that we've confirmed that authentication works, if your controller tests fail, you can assume that it's not because of authentication issues.

# Step 3. Add your helper methods to tests that require authentication #

Going back to our books app example - the controller test for adding new books needs to have authentication tokens in the HTTP request. So take the following steps.

## 1) Require and include your helper file ##
Include the helper file in the controller test where you're using authentication.
```ruby
# Please use your actual relative path to this file.
require_relative '../helpers/authorization_helper'
```

Also, include this module like so.
```ruby
class BooksControllerTest < ActionDispatch::IntegrationTest
include AuthorizationHelper
end
```

## 2) Authenticate in the setup method ##
The `setup` method is called before every test, so put your authentication method here to avoid redundant code.

```ruby
def setup
  test_user = { email: 'user@test.com', password: 'testuser' }
  sign_up(test_user)
  @auth_tokens = auth_tokens_for_user(test_user)
  end
```

## 3) Include the auth tokens in the headers ##
Then, simply include the auth tokens in the headers of your test. It's as simple as adding one line like below.


```ruby
test 'should create new book' do
  post 'books/',
    params: {
    name: 'Harry Potter'
    },
    headers: @auth_tokens

    assert_response :success
end
```


And that's it! We've covered how to write tests for authorization code and how to send authenticated HTTP requests in other tests. Thank you for reading, and please let me know if anything needs clarifying.