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.