Coding

Ruby on Rails: Building a RESTful API with Ruby on Rails and JWT Authentication

In this tutorial, we'll guide you through building a secure RESTful API in Rails, using JSON Web Tokens (JWT) for authentication. This API will be suitable for backends that power mobile apps or single-page applications (SPAs).

Prerequisites
  • . Basic knowledge of Ruby on Rails.
  • . Familiarity with API development and concepts of authentication.
  • . Rails 6 or later installed on your machine.

Step 1: Setting Up the Rails API

1.1 Create a New Rails Application
To begin, create a new Rails API application. Rails allows you to create a lightweight API-only application using the --api flag.

rails new jwt_api --api
cd jwt_api

This will generate a new Rails app with only the essentials needed for an API, excluding view templates, assets, and other frontend components.

1.2 Add Necessary Gems
We need a couple of gems for JWT authentication and password security:

  • . bcrypt for hashing passwords.
  • . jwt for generating and verifying JSON Web Tokens.

Add these to your Gemfile: 
# Gemfile
gem 'bcrypt', '~> 3.1.7'
gem 'jwt'

 Then run: 
bundle install

Step 2: Set Up User Model and Authentication

2.1 Generate the User Model
 We'll create a User model that will handle user registration and authentication. This model will use bcrypt to securely store hashed passwords. 

rails generate model User email:string password_digest:string
rails db:migrate

 Update the User model to include password handling: 
# app/models/user.rb
class User < ApplicationRecord
  has_secure_password

  validates :email, presence: true, uniqueness: true
end

The has_secure_password method, provided by bcrypt, adds methods to set and authenticate users via passwords.

2.2 Create the Users Controller

Now, we'll create a controller to handle user registration. This will be the endpoint where users can sign up.
rails generate controller Users

 In the UsersController, create an action for user registration: 
# app/controllers/users_controller.rb
class UsersController < ApplicationController
  def create
    user = User.new(user_params)
    if user.save
      render json: { user: user, message: 'User created successfully' }, status: :created
    else
      render json: { errors: user.errors.full_messages }, status: :unprocessable_entity
    end
  end

  private

  def user_params
    params.require(:user).permit(:email, :password, :password_confirmation)
  end
end

 Update your routes.rb file to add a route for user registration: 
# config/routes.rb
Rails.application.routes.draw do
  resources :users, only: [:create]
end

Now, you can test user registration with a POST request to /users by sending an email and password.

Step 3: Implement JWT Authentication

3.1 Create Authentication Controller

We'll create an AuthController to handle user login and issue JWT tokens.
rails generate controller Auth

 In the AuthController, add a login action: 
# app/controllers/auth_controller.rb
class AuthController < ApplicationController
  def login
    user = User.find_by(email: params[:email])

    if user&.authenticate(params[:password])
      token = encode_token({ user_id: user.id })
      render json: { token: token, message: 'Login successful' }, status: :ok
    else
      render json: { errors: 'Invalid email or password' }, status: :unauthorized
    end
  end

  private

  # Helper method to encode the token
  def encode_token(payload)
    JWT.encode(payload, Rails.application.secrets.secret_key_base)
  end
end

This method:

  • . Authenticates the user with the given email and password.
  • . If successful, it generates a JWT using the encode_token method and returns it to the client.
Add a route for the login endpoint:
# config/routes.rb
Rails.application.routes.draw do
  resources :users, only: [:create]
  post '/login', to: 'auth#login'
end

3.2 Decode and Authorize JWT

Next, we need to add functionality to verify and decode the JWT for protected routes. Let’s create a current_user method in the ApplicationController that will be used to retrieve the logged-in user based on the token.
# app/controllers/application_controller.rb
class ApplicationController < ActionController::API
  before_action :authorized

  def authorized
    render json: { message: 'Please log in' }, status: :unauthorized unless logged_in?
  end

  private

  def logged_in?
    !!current_user
  end

  def current_user
    if decoded_token
      user_id = decoded_token[0]['user_id']
      @current_user ||= User.find_by(id: user_id)
    end
  end

  def decoded_token
    if auth_header
      token = auth_header.split(' ')[1]
      begin
        JWT.decode(token, Rails.application.secrets.secret_key_base, true, algorithm: 'HS256')
      rescue JWT::DecodeError
        nil
      end
    end
  end

  def auth_header
    request.headers['Authorization']
  end
end

This:

  • . Retrieves the token from the Authorization header.
  • . Decodes the token to get the user’s ID.
  • . Returns the current user based on the decoded token.
  • . Ensures that all protected routes require a logged-in user by calling authorized.
You can test this by adding before_action :authorized to any controller to protect its actions.

Step 4: Secure an Endpoint
Let’s create a protected endpoint that only logged-in users can access.

Generate a PostsController:
rails generate controller Posts

 Add the following code to protect the index action so only authenticated users can access it: 
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def index
    posts = Post.all
    render json: posts
  end
end

 Add a route for Posts: 
# config/routes.rb
Rails.application.routes.draw do
  resources :users, only: [:create]
  post '/login', to: 'auth#login'
  resources :posts, only: [:index]
end

Now, when trying to access /posts, you must include a valid JWT token in the Authorization header, or the request will be denied.

Step 5: Testing the API

5.1 Register a User
You can test the user registration by sending a POST request to /users:
POST /users
{
  "user": {
    "email": "[email protected]",
    "password": "password123",
    "password_confirmation": "password123"
  }
}

5.2 Log In to Get a Token

Next, test the login endpoint by sending a POST request to /login:
POST /login
{
  "email": "[email protected]",
  "password": "password123"
}

 If successful, the response will include a JWT token: 
{
  "token": "your.jwt.token.here",
  "message": "Login successful"
}

5.3 Access Protected Resources

Now, use this token to access the /posts endpoint. Include the JWT token in the Authorization header:
GET /posts
Authorization: Bearer your.jwt.token.here

If the token is valid, you'll receive a list of posts. Otherwise, you’ll get an "unauthorized" error.

Conclusion
In this tutorial, we’ve built a secure RESTful API using Rails and JWT authentication. We’ve covered:

  • . Setting up user authentication with bcrypt.
  • . Implementing JWT token generation and verification.
  • . Protecting API endpoints and authorizing users with tokens.
By understanding how to implement JWT in Rails, you can secure your API and use it as a backend for mobile apps or single-page applications (SPAs). From here, you can enhance the
API with features like role-based access control, token expiration, and refresh tokens for even more robust authentication.



No comment
Leave a Reply

Your email adress will not be published ,Requied fileds are marked*.

Hi, I'm Kenroy Reid

Hello there

More Form Aurthor
Categories

Get The Best Blog Stories into Your inbox!

Sign up for free and be the first to get notified about new posts.