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.