Okay now we’re ready to generate rails project, type this on your terminal
$ rails new rails-jwt --api
Add Json Web Token (JWT) and bcrypt gem
- JWT : Token encoder / decoder with expiration time
- bcrypt : Password encryption
# Use Json Web Token (JWT) for token based authenticationgem 'jwt'
# Use ActiveModel has_secure_passwordgem 'bcrypt', '~> 3.1.7'
and then install dependencies by typing this on your terminal
$ bundle install
Update routes
# config/routes.rbRails.application.routes.draw do resources :users, param: :_username post '/auth/login', to: 'authentication#login' get '/*a', to: 'application#not_found' end
======================================================================
Add new file: app/lib/json_web_token.rb
| class JsonWebToken | |
| SECRET_KEY = Rails.application.secrets.secret_key_base. to_s | |
| def self.encode(payload, exp = 24.hours.from_now) | |
| payload[:exp] = exp.to_i | |
| JWT.encode(payload, SECRET_KEY) | |
| end | |
| def self.decode(token) | |
| decoded = JWT.decode(token, SECRET_KEY)[0] | |
| HashWithIndifferentAccess.new decoded | |
| end | |
| end | 
=======================================================================
For Application controller:
class ApplicationController < ActionController::API
 def not_found
    render json: { error: 'not_found' }
  end
  def authorize_request
    header = request.headers['Token']
    header = header.split(' ').last if header
    begin
      @decoded = JsonWebToken.decode(header)
      @current_user = User.find(@decoded[:user_id])
    rescue ActiveRecord::RecordNotFound => e
      render json: { errors: e.message }, status: :unauthorized
    rescue JWT::DecodeError => e
      render json: { errors: e.message }, status: :unauthorized
    end
  end
end
=====================================================================
Create user model
$ rails g model user name:string username:string email:string password_digest:string
===================================================================
Add user.rb:
| class User < ApplicationRecord | |
| has_secure_password | |
| mount_uploader :avatar, AvatarUploader | |
| validates :email, presence: true, uniqueness: true | |
| validates :email, format: { with: URI::MailTo::EMAIL_REGEXP } | |
| validates :username, presence: true, uniqueness: true | |
| validates :password, | |
| length: { minimum: 6 }, | |
| if: -> { new_record? || !password.nil? } | |
| end | 
========================================================================
Create user controller
$ rails g controller users
class UsersController < ApplicationController
  before_action :authorize_request, except: :create
  before_action :find_user, except: %i[create index]
  # GET /users
  def index
    @users = User.all
    render json: @users, status: :ok
  end
  # GET /users/{username}
  def show
    render json: @user, status: :ok
  end
  # POST /users
  def create
    @user = User.new(user_params)
    if @user.save
      render json: @user, status: :created
    else
      render json: { errors: @user.errors.full_messages },
             status: :unprocessable_entity
    end
  end
  # PUT /users/{username}
  def update
    unless @user.update(user_params)
      render json: { errors: @user.errors.full_messages },
             status: :unprocessable_entity
    end
  end
  # DELETE /users/{username}
  def destroy
    @user.destroy
  end
  private
  def find_user
    @user = User.find_by_username!(params[:_username])
    rescue ActiveRecord::RecordNotFound
      render json: { errors: 'User not found' }, status: :not_found
  end
  def user_params
    params.permit(
      :avatar, :name, :username, :email, :password, :password_confirmation
    )
  end
end
======================================================================
Create authentication controller
$ rails g controller authentication
| before_action :authorize_request, except: :login | |
| # POST /auth/login | |
| def login | |
| @user = User.find_by_email(params[:email]) | |
| if @user&.authenticate(params[:password]) | |
| token = JsonWebToken.encode(user_id: @user.id) | |
| time = Time.now + 24.hours.to_i | |
| render json: { token: token, exp: time.strftime("%m-%d-%Y %H:%M"), | |
| username: @user.username }, status: :ok | |
| else | |
| render json: { error: 'unauthorized' }, status: :unauthorized | |
| end | |
| end | |
| private | |
| def login_params | |
| params.permit(:email, :password) | |
| end | 
=======================================================================
Add a app/config/application.rb
load_path_strategy = Rails.env.production? ? :eager_load_paths : :autoload_paths
    config.public_send(load_path_strategy) << Rails.root.join('lib')
