How to Secure REST APIs in React
Securing REST APIs in React applications is crucial for protecting sensitive user data and preventing unauthorized access. While React runs entirely on the client side, robust security requires a combination of secure token storage, proper state management, protected routing, and backend coordination. This article explores the best practices for securing your APIs, including implementing JSON Web Tokens (JWT), safeguarding API keys, handling HTTP-only cookies, and configuring network interceptors.
Store Authentication Tokens Securely
When your React app authenticates with a REST API, it typically receives a JSON Web Token (JWT). How you store this token determines your vulnerability to Cross-Site Scripting (XSS) attacks.
- Avoid LocalStorage and SessionStorage: Storing
tokens in
localStoragemakes them accessible to any JavaScript running on your page, including malicious third-party scripts. - Use HTTP-Only Cookies: The most secure way to store
JWTs is in an
httpOnlycookie. This flag prevents client-side JavaScript from reading the cookie, effectively neutralizing XSS token theft.
Implement Request Interceptors for Authorization
If your architecture requires passing tokens manually via Authorization headers (e.g., Bearer tokens), use Axios or Fetch interceptors. Interceptors automatically attach the token to every outgoing request without duplicating code.
// Example using Axios Interceptor
axios.interceptors.request.use(
(config) => {
const token = getAuthToken(); // Retrieve token from a secure memory state
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);Protect Frontend Routes
While frontend routing cannot replace backend API security, it improves user experience by blocking unauthenticated users from accessing private UI components. Use React Router to build a protected route wrapper.
import { Navigate, Outlet } from 'react-router-dom';
const ProtectedRoute = ({ isAuthenticated }) => {
return isAuthenticated ? <Outlet /> : <Navigate to="/login" replace />;
};Ensure that your backend API also validates the token for every request, as a user could easily bypass React-side route guards by manipulating the local application state.
Use a Backend Proxy for API Keys
React applications are compiled and shipped directly to the browser.
Any environment variable prefixed with REACT_APP_ or
VITE_ is visible in the source code.
To secure sensitive third-party API keys: 1. Create a lightweight backend proxy (e.g., Node.js/Express). 2. Keep your secret API keys on the backend server. 3. Have your React app request data from your own proxy server, which then forwards the request to the third-party API with the hidden key.
Enable Cross-Origin Resource Sharing (CORS)
CORS is a browser security mechanism that restricts resources on a
web page from being requested from another domain. Configure your REST
API server to only accept requests originating from your React
application’s specific domain (e.g.,
https://myreactapp.com) rather than allowing wildcard
access (*).
Implement Content Security Policy (CSP)
A Content Security Policy (CSP) is an HTTP header sent by your server that tells the browser which dynamic resources are allowed to load. Implementing a strict CSP prevents unauthorized scripts from executing in your React application, protecting your API connections from data exfiltration.