DEV Community

Cover image for Create a Rails 7 API with JWT in 2023
Alexander Kustov
Alexander Kustov

Posted on

Create a Rails 7 API with JWT in 2023

Make sure you're running the latest stable Rails, Rails 7.0.4.2

  • Create a new Rails app with the --api option to generate an API-only Rails app:

rails new my_rails_jwt_api --api

  • Add the jwt gem to your Gemfile and run bundle install to install it:

gem 'jwt'

  • Uncomment the bcrypt gem in your Gemfile and run bundle install to install it:

gem "bcrypt", "~> 3.1.7"

  • Generate a User model with the necessary attributes for authentication (e.g. email and password_digest):

rails g model User email password_digest

  • Add has_secure_password to your User model to encrypt the password:
class User < ApplicationRecord
  has_secure_password
end
Enter fullscreen mode Exit fullscreen mode
  • Create a SessionsController to handle user authentication:

rails g controller Sessions

  • In the SessionsController, create an action that accepts a user's credentials (e.g. email and password) and returns a JWT if the credentials are valid:
class SessionsController < ApplicationController
  skip_before_action :authenticate_request

  def create
    user = User.find_by(email: params[:email])
    if user&.authenticate(params[:password])
      jwt = JWT.encode({ user_id: user.id }, Rails.application.secrets.secret_key_base)
      render json: { jwt: jwt }
    else
      render json: { error: 'Invalid credentials' }, status: :unauthorized
    end
  end
end
Enter fullscreen mode Exit fullscreen mode
  • Note that we're using Rails' secrets.secret_key_base to sign the JWT. You can generate a secret key with rails secret.

  • In your ApplicationController, define a method to extract the JWT from the request headers and verify it:

class ApplicationController < ActionController::API
  before_action :authenticate_request

  def authenticate_request
    header = request.headers['Authorization']
    token = header.split(' ').last if header
    begin
      decoded = JWT.decode(token, Rails.application.secrets.secret_key_base, true, algorithm: 'HS256')
      @current_user_id = decoded[0]['user_id']
    rescue JWT::DecodeError
      render json: { error: 'Invalid token' }, status: :unauthorized
    end
  end
end
Enter fullscreen mode Exit fullscreen mode
  • This will extract the JWT from the Authorization header and decode it using the same secret key as before. If the JWT is valid, we set @current_user_id to the user ID contained in the token.

  • Finally, create an action in one of your controllers that requires authentication, and use @current_user_id to access the current user's data:

class UsersController < ApplicationController
   def show
     user = User.find(@current_user_id)
    render json: user
   end
end
Enter fullscreen mode Exit fullscreen mode

-Don't forget the routes


Rails.application.routes.draw do
  resources :users, only: [:show]
  resources :sessions, only: [:create]
end

Enter fullscreen mode Exit fullscreen mode
  • That's it! This is just a basic example, and there are many ways to implement JWT authentication in a Rails app. But this should give you a good starting point.

Top comments (3)

Collapse
 
tnypxl profile image
tnypxl •

Did you run this code and make sure it works, or did you paste this straight out of ChatGPT?

Collapse
 
alexanderkustov profile image
Alexander Kustov •

Thank you for your comment. As an AI language model, I do not have the capability to run code or execute commands. However, I am designed to provide helpful and informative responses to various inquiries. If there is anything specific you need assistance with, I would be more than happy to help to the best of my abilities.

Collapse
 
tnypxl profile image
tnypxl •

Oh, wow. Thank you for enlightening me on your limitations as an AI language model. I had no idea that you were incapable of running code or executing commands. I thought you were capable of doing everything, including making me a cup of coffee. Silly me! But thanks for being so helpful and informative in your responses. I'll make sure to keep my expectations in check.