JWT Token-based custom user authentication for Rails API only (Part 01)
Tags: rails, jwt, api, authentication
Published: 2021-05-28 05:41:34

I have been using _[Devise Token Auth](https://rubygems.org/gems/devise_token_auth)_ gem for Rails API only projects. 

There seems some issues with this gem: 
- First, _devise token auth_ is an extension of _[devise gem](https://rubygems.org/gems/devise)_ which has majority settings that _devise token auth_ uses.
- Second is through gem we get great many settings of _devise_ and _devise token auth_ by which we need not use in day to day projects.
- Third due to usage of two gems parent and child, we need to know all the documentation of both gems to work appropriately with this.
- Furthermore, we don’t get much control over our authentication system that we build because of dependency of gems.

These issues led to build my authentication system that I code customise the code myself on day to day based on the project that I am working on.

> This tutorial doesn’t intend to demonstrate another gem as I felt it would be better not to create a gem with settings. Rather I wanted to have the code and concept so that I can duplicate and change all the stuff according to the project.

---- 

## Concepts

What a good authentication system initial concepts involve for APIs?

- First there should be a _user_ model on which we want to implement authentication. _User_ should have at least email and hashed password for authentication.
- Second there should normally be a session of the user which can be used for request authentication. But as APIs are complete cut off with the browser page so only requests/responses are the connection with the server. So, when the response completes, session gets closed. So, we need to have some session token passed to the server which verifies the user and gives response. This is called **Token-based Authentication System**.
- There should be a way that a user can be logged in at the same time to multiple devices like phone, tablet, computer. So, we will need different sessions for the same user.
- User should be able to confirm his/her email and reset her/her password as well.
- Finally, User should be able to log in with _OAuth_, i.e., Google, Facebook ETC.

In this tutorial, We will look into all this concepts and makes our code fulfilling these concepts. The First time devs creating their code will think of this tutorial as against convention over configuration. But when you put these concepts to use in different projects, you will consider it to be great because you will be able to change/debug everything easily then.

---- 

## Code Repo

{% github sulmanweb/rails-api-user-custom-auth no-readme %}

---- 

# Project Initiation

I use the docker-compose system to initiating the api for rails. Tutorial is given **[here](https://dev.to/sulmanweb/initialise-rails-api-backend-and-vuejs-app-frontend-in-docker-for-development-3ab2)**.

So, I am assuming that you have initialised the rails project.

## Step 1 — Create User Model

Create user model by following command:  

```bash
rails g model User name:string email:string:uniq password_digest:string email_confirmed_at:datetime:index
```

You may have noticed that we entered `password_digest` not password. As we will be using _[bcrypt gem](https://rubygems.org/gems/bcrypt)_ for hashing user passwords. Add this to gemfile and run `bundle install`. Their documentation says just do below two things and all passwords will be hashed:

1. Name the column for password storage as `password_digest`.
2. Add line `has_secure_token` in `app/models/user.rb` file.

So, we will now have user model after above command, run migration and if you access the console and create a user, then you will see that `password_digest` column has gibberish values.

## Step 2 — Create Session Model

Now create a session model. A user can have many sessions and a session belongs to a user. The Session model contains the last used timestamp so that we can check when was this session last used by the user. Status that tells if this session is active or not. A token column that saves a unique string to verify the session. Create a session model by calling:

```bash
rails g model Session user:references last_used_at:datetime:index status:boolean:index token:string:uniq
```

## Step 3 — Create User Verification Model

Now create a model that will work for user confirm email or user’s reset password. This model will have an extra `verify_type` column that will contain options to have different  verification systems for future.

```bash
rails g model UserVerification user:references status:string:index token:string:uniq verify_type:string:index
```

---- 

These are all the models we need for now to create our authentication system. In the next article we will work on controller designs for authentication.