Setting up JWT in Rails API Backend for React frontend

evanrpavone

EvanRPavone

Posted on February 26, 2021

Setting up JWT in Rails API Backend for React frontend

I just want to start off by saying, I did not really focus on my User Login, this is just my experience setting it up.

Gems

The gems I used are as followed:

  • bcrypt
  • dotenv-rails
  • jwt

I used the JSON Web Token (JWT) gem in my rails backend, this helped out using authentication in the frontend. Setting this up was very confusing and frustrating. Luckily google is a thing and that helped me out a lot (I will have a link for what really helped me out). A lot of things that I will be saying in this probably wont make sense, I am not the best at explaining stuff.

Models

I started by creating a User model with username and password (password_digest). This was the first thing I did before implementing all my other models, I just wanted to get this out of the way.

class User < ApplicationRecord
    has_secure_password
    validates :username, presence: true, uniqueness: true
    validates :password, presence: true
end
Enter fullscreen mode Exit fullscreen mode

Controllers

There are 3 controllers that help with user authentication:

  • application_controller (this is where you configure your JWT)
  • users_controller
  • sessions_controller
application_controller
class ApplicationController < ActionController::API

    def jwt_key
        ENV['SESSION_SECRET']
    end

    def issue_token(user)
        JWT.encode({user_id: user.id}, jwt_key, 'HS256')
    end
    def decoded_token
        begin
            JWT.decode(token, jwt_key, true, { :algorithm => 'HS256' })
        rescue JWT::DecodeError
            [{error: "Invalid Token"}]
        end
    end

    def token
        request.headers['Authorization']
    end
    def user_id
        decoded_token.first['user_id']
    end
    def current_user
        @user ||= User.find_by(id: user_id)
    end
    def logged_in?
        !!current_user
    end
end
Enter fullscreen mode Exit fullscreen mode

This is where I needed to google. I found examples that used the dotenv gem to hide my sessions secret which was the JWT token. You can get your own JWT token by going to JWT Website, scroll down under Debugger and find something that looks like this:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),

  your-256-bit-secret (This is what you want)

) secret base64 encoded
Enter fullscreen mode Exit fullscreen mode

rename your-256-bit-secret to whatever you want, make it lengthy. It will tell you if it is okay to use. Paste your secret into your dotenv like this:
SESSION_SECRET = your-256-bit-secret

users_controller

This controller is pretty simple to setup. You just need a create method and a user params. This is my create method. I recommend using it:

    def create
        user = User.new(user_params)
        if user.save
            token = issue_token(user)
            render json: { valid: "true", user: {id: user.id, username: user.username}, token: token}
        else
            render json: { valid: "false", errorMessages: user.errors.messages }
        end
    end
Enter fullscreen mode Exit fullscreen mode

For the user_params just permit username and password.

sessions_controller

This controller is used to authenticate if your username and password is correct and if the current user is you. It also issues a token from jwt each time a session is created. This has two methods in it, create and show:

    def create
        user = User.find_by(username: params[:username])
        if user&.authenticate(params[:password])
            token = issue_token(user)
            render json: { valid: "true", user: {id: user.id, username: user.username}, token: token}
        else
            render json: { valid: "false", errorMessages: {login: "username or password is wrong"} }
        end
    end

    def show
        if logged_in?
            render json: { valid: "true", user: {id: current_user.id, username: current_user.username} }
        else
            render json: { valid: "false", errorMessages: {session: "Please login to continue"}}
        end
    end
Enter fullscreen mode Exit fullscreen mode

Routes

  post '/login', to: 'sessions#create'
  get '/authorize', to: 'sessions#show'
Enter fullscreen mode Exit fullscreen mode

When the user logs in it will make a new session and it will authorize to see if you are logged in.

Thats the rest for the backend. Sorry if I didn't explain it that well but most of this stuff I found googling.

Conclusion

When I setup my frontend to have a user login function, it was a pretty easy for me from that point on. I know I didn't explain everything fully in-depth but I hope this helped. I personally don't know if this is the proper way. Make sure to check out the link below for more information regarding JWT setup.

Resources

JWT Setup - Kailana Kahawaii explains it more in depth. This is what really helped me out setting this up, so if you want a more in-depth tutorial, check this blog out.

💖 💪 🙅 🚩
evanrpavone
EvanRPavone

Posted on February 26, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related