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.