User Authentication Using Rails and React

Authenticate users using a Rails API backend with session/JWT support and a React frontend managing auth flow, protected routes, and login state

System Overview

[ React Frontend ]  <----HTTP---->  [ Rails API Backend ]       |                                  |   Login Form  <------POST /login-------> |        |                                  |    Stores JWT/Session <---Response------- |        |                                  |    Authenticated Requests --------------> |
  • Frontend: React handles UI, stores auth state, sends credentials.
  • Backend: Rails provides API endpoints for signup, login, user data, manages sessions or JWT.

Rails API: Authentication Endpoints

Set up secure Rails API endpoints for signup, login, session handling, and CSRF protection.

User Model & Controller

  • Add authentication gems (e.g., bcrypt for password hashing):
gem install bcrypt
Example User model:
# app/models/user.rbclass User < ApplicationRecord   has_secure_password end
Example Registrations controller:
# app/controllers/registrations_controller.rbclass RegistrationsController < ApplicationController   def create     user = User.create!(       email: params["user"]["email"],       password: params["user"]["password"],       password_confirmation: params["user"]["password_confirmation"]     )     if user       session[:user_id] = user.id       render json: { status: :created, user: user }     else       render json: { status: 500 }     end   end end

Session Management

Example Sessions controller for login/logout:
# app/controllers/sessions_controller.rbclass SessionsController < ApplicationController   def create     user = User.find_by(email: params[:email])     if user&.authenticate(params[:password])       session[:user_id] = user.id       render json: { logged_in: true, user: user }     else       render json: { logged_in: false, error: 'Invalid credentials' }     end   end     def is_logged_in?     if session[:user_id]       user = User.find(session[:user_id])       render json: { logged_in: true, user: user }     else       render json: { logged_in: false }     end   end     def destroy     reset_session     render json: { logged_out: true }   end end
CSRF: For API-only Rails apps, disable CSRF protection:
# app/controllers/application_controller.rbclass ApplicationController < ActionController::Base   skip_before_action :verify_authenticity_token end

React Frontend: Authentication Flow

Now let’s implement the frontend logic to manage authentication state and securely communicate with the Rails API.

State Management & API Calls

Use Redux or React Context to manage authentication state.

Example Redux slice:
// reducers/user.jsexport default (state = { isLoggedIn: false, id: null, username: '' }, action) => {   switch (action.type) {     case 'LOGIN_USER':       return { isLoggedIn: true, id: action.user.id, username: action.user.username };     case 'LOGOUT_USER':       return { isLoggedIn: false, id: null, username: '' };     default:       return state;   } };
Example API call for login:
// actions/login.jsexport const loginUser = (email, password) => dispatch => {   fetch('/login', {     method: 'POST',     headers: { 'Content-Type': 'application/json' },     body: JSON.stringify({ email, password }),     credentials: 'include', // important for cookies/session   })   .then(res => res.json())   .then(data => {     if (data.logged_in) {       dispatch({ type: 'LOGIN_USER', user: data.user });     }   }); };

Authenticated Routing

Protect private routes by checking authentication state and redirecting unauthenticated users using React Router.

Use React Router to restrict access:
// PrivateRoute.jsimport { useSelector } from 'react-redux'; export default function PrivateRoute({ children }) {   const isLoggedIn = useSelector(state => state.user.isLoggedIn);   return isLoggedIn ? children : <Redirect to="/login" />; }
Also Read: ReactJS forwardRef: A Comprehensive Guide

Session or JWT?

  • Session-based: Rails manages session cookies (simpler, works if frontend and backend share a domain or CORS is configured).
  • JWT-based: Use gems like knock or devise-jwt for token-based authentication15. React stores the JWT (preferably in memory or HttpOnly cookies).

Quick Reference: Rails API Routes

# config/routes.rbpost '/signup', to: 'registrations#create' post '/login', to: 'sessions#create' delete '/logout', to: 'sessions#destroy' get '/logged_in', to: 'sessions#is_logged_in?'

Pro Tips

  • Always hash passwords using has_secure_password (bcrypt).
  • Use HttpOnly cookies for session/JWT storage to prevent XSS.
  • Configure CORS in Rails for cross-origin requests from React.
  • Never expose sensitive user data in API responses.
  • Centralize auth state in React for a smooth UX.

End-to-End Flow Recap

  • User signs up or logs in via React form.
  • React sends credentials to Rails API.
  • Rails authenticates and sets session/JWT.
  • React stores auth state and restricts routes.
  • User stays authenticated until logout.
Related

Why am I getting this problem? If you apply separate filters in sequence or only check one property at a time your code will match…

22 Oct, 2025

Why am I getting this problem? By default, rendering a table in React just displays data in its original order. Clicking the header won’t sort…

15 Oct, 2025

Understanding the Problem When building React applications, especially Single Page Applications (SPAs) using React Router, you might expect the page to scroll to the top…

10 Oct, 2025