Setting up JWT in Rails API Backend for React frontend
Tags: rails, api, jwt
Published: 2021-02-26 19:06:17

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
```

#### 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
```
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](https://jwt.io/), 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
```
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
```
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
```
#### Routes
```
  post '/login', to: 'sessions#create'
  get '/authorize', to: 'sessions#show'
```
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](https://dev.to/kahawaiikailana/rails-api-quickstart-guide-with-postgressql-and-jwt-tokens-3pnk) - 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.