It is quite common to add authentication to your web or mobile app. The most common and easiest to set up for mobile apps and javascript clients that connect to Rails APIs is using JWT(JSON Web Tokens). They can be stored by you Javascript client( such as Angular, React, and Vue) and sent using each request to authenticate with your API. In this tutorial, I’ll show you how to authenticate using this method. You can also check out our repo here or check out some of our courses that involve JWT authentication and SPA development.

Project Setup

Let’s get started by scaffolding our applications. We’ll scaffold a TodoList so we can later use to test protecting our request from unauthorized users with JWT generated using Knock.

Create the new Rails app with

rails new knock-todo --api --skip --database=postgresql

Then generate the todolist with

rails generate scaffold Todo title:string finished:boolean

You’ll get a rails migration that looks like this

class CreateTodos < ActiveRecord::Migration[5.2]
  def change
    create_table :todos do |t|
      t.string :title
      t.boolean :finished

      t.timestamps
    end
  end
end

Also your rails JSON templates for you Todo API and Routes will be generated.

Generate Knock Users

Next, we will generate out user to be used with Knock.

rails generate scaffold User email:string password_digest:string

Password_Digest is a field that will be used by Knock to store hashed passwords

class CreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      t.string :email
      t.string :password_digest

      t.timestamps
    end
    add_index :users, :email
  end
end

Now you can add knock and bycrpt to your gem file and install it in the command line

gem 'knock'
gem 'bcrypt'

Now, inside of your rails User model, make sure you have has_secure_password as your authentication method. We’ll also validate the presence of an email and create a token payload function to return the user id and the email inside of the token.

class User < ApplicationRecord
    has_secure_password
    validates :email, presence: true

    def to_token_payload
        {
            sub: id,
            email: email
        }
    end
end
bundle install
rails generate knock:install

This will generate a file “config/initializers/knock.rb” that is used to modify the default configuration of your token. You can change things such as its Signature algorithm and Key.

Now, in order to create an endpoint to generate your tokens, you must run

rails generate knock:token_controller user

This creates the ruby on rails controller user_token_controller.rb and adds a post route to your controller for creating the JWT token.

class UserTokenController < Knock::AuthTokenController
end


post 'user_token' => 'user_token#create'

One last thing will be to change the user params inside of your user controller.

Change

def 
    user_params
  params.require(:user).permit(:email, :password_digest)

end

to

def user_params
      params.require(:user).permit(:email, :password, :password_confirmation)
 end

If you don’t do this, you’ll end up with a 422 error.

422 User Creation Error

422 User Creation Error

Creating Rails Users and Returning a Knock JWT token

Let’s test out creating our first use. Using an API testing client like Postman or Insomnia, post a JSON object to the create users route with new user credentials.

Let’s create an object that looks like this

{
	"user": {
		"email": "james@gmail.com",
		"password": "Pokemon43!"
	}
}

You should get a 201 status returned to you.

User Creation

User Creation

Now we can try creating a Knock JWT using those same credentials.

{
	"auth": {
		"email": "james@gmail.com",
		"password": "Pokemon43!"
	} 
}

OOOps, If you get this error then that most likely means you’re using Rails 5.2 and above. This is caused by protect_from_forgery being include in ActionController::Base by default.

422 CSRF

422 CSRF

We can fix this error by adding as skip_before_action

class UserTokenController < Knock::AuthTokenController
  
      skip_before_action :verify_authenticity_token, raise: false

end

Also inside of our Knock config, we want to set how we sign our token.

config.token_secret_signature_key = -> { Rails.application.credentials.fetch(:secret_key_base) }

We should be able to get our token one this change is added.

Successful Token

Successful Token

Guarding Our Routes

Now that we have token auth set up, we can finally protect our routes from unauthenticated users.

Let’s go to our todos controller and add

before_action :authenticate_user

This will protect the controller from unauthenticated users

Now let’s try hitting out route http://localhost:3000/todos. We’ll get a 401 error

401 Error Unauthorized

401 Error Unauthorized

Now let’s try again with a Bearer Token in the header

We’ll now be able to get our JSON

Success Auth Request

Success Auth Request

Conclusion

Using JWT is one of the best ways to authenticate your API against SPA(Single Page Application) like React or Vue. JWT authentication is also a technique that can be used with Mobile applications. If you’re interested in learning more, check out our repo here or check out some of our courses that involve JWT authentication and SPA development.

Codebrains Newsletter

Get weekly dev news and tutorials.

Powered by ConvertKit