React Authentication Pitfalls
/ 2 min read
Table of Contents
React Authentication Pitfalls and How to Fix Them
Authentication is a critical part of web applications, but mistakes can lead to token leaks, session hijacking, and unauthorized access.
This guide covers:
- Handling JWTs securely
- Preventing session fixation
- OAuth implementation risks
- Secure login form best practices
1. Storing JWTs in Local Storage is a Security Risk
JWTs stored in localStorage
are vulnerable to XSS attacks.
If an attacker injects malicious JavaScript, they can steal the token.
Bad: Storing JWTs in localStorage
localStorage.setItem("token", jwtToken);
Fix: Use Secure HTTP-Only Cookies
HTTP-only cookies prevent JavaScript access, protecting tokens from XSS.
// Server-side (Express.js)import cookieParser from "cookie-parser";
app.use(cookieParser());app.post("/login", (req, res) => { res.cookie("auth_token", "secure-token", { httpOnly: true, secure: true, sameSite: "Strict", }); res.send("Logged in");});
2. Session Fixation: Reusing Session IDs After Login
If a session ID is not refreshed after login, an attacker with a pre-login session can hijack it.
Fix: Regenerate Session After Authentication
// Server-side (Express.js)app.post("/login", (req, res) => { req.session.regenerate(() => { req.session.userId = user.id; res.send("Session refreshed"); });});
3. OAuth Redirect Vulnerabilities
OAuth login redirects users to an authentication provider, but attackers can manipulate redirect URIs to steal authentication tokens.
Bad: Accepting Any Redirect URL
const redirectUrl = new URLSearchParams(window.location.search).get("redirect");
window.location.href = redirectUrl;
Fix: Validate Allowed Redirects
const allowedRedirects = ["https://yourapp.com/dashboard"];
const redirectUrl = new URLSearchParams(window.location.search).get("redirect");if (!redirectUrl || !allowedRedirects.includes(redirectUrl)) { throw new Error("Invalid redirect URL");}window.location.href = redirectUrl;
4. Exposing User Data in JWT Payloads
JWTs store data in base64 format, meaning anyone can decode them.
If sensitive information is stored inside, it can be exposed in the frontend.
Bad: Storing Sensitive Data in JWT
// JWT Payload{"userId": "123","role": "admin","email": "user@example.com"}
Fix: Store Minimal Information in JWT
Use the JWT only for authentication, and store user details in the database.
// Safe JWT Payload{"userId": "123"}
5. Weak Password Handling and Bruteforce Risks
Allowing short, simple passwords and lacking brute-force protection makes logins vulnerable.
Fix: Enforce Strong Passwords
Use libraries like zxcvbn to validate passwords.
import zxcvbn from "zxcvbn";
const passwordStrength = zxcvbn(password);if (passwordStrength.score < 3) { console.log("Weak password");}
Fix: Implement Rate Limiting
Prevent brute-force attacks by limiting login attempts.
import rateLimit from "express-rate-limit";
const limiter = rateLimit({ windowMs: 15 _ 60 _ 1000, max: 5 });
app.use("/login", limiter);
Conclusion
- Store JWTs in HTTP-only cookies, not
localStorage
. - Regenerate session IDs after login to prevent fixation.
- Validate OAuth redirects to prevent token leaks.
- Minimize data stored in JWTs to prevent exposure.
- Enforce strong passwords and rate limiting to secure logins.
Securing authentication requires multiple layers of defense.
Implement these fixes before attackers find the weaknesses.