6.3 KiB
Great — now we’re connecting both ends of your application. Let’s walk through how authentication and authorization flow works on the frontend side (React) when using JWT-based authentication with a backend API.
🔁 Overall Frontend Authentication Flow (React + JWT)
-
User logs in:
-
They submit credentials (username/password) via a login form.
-
Frontend sends a POST request to
/api/auth/login. -
Backend validates and responds with a JWT (and optionally a refresh token).
-
-
Frontend stores the token:
-
This is usually saved in:
-
localStorage✅ simple, persistent -
or an HttpOnly cookie ✅ safer, but needs server support
-
-
-
Frontend sends the token on future API calls:
-
Automatically attaches the token as a header:
Authorization: Bearer <token>
-
-
Frontend restricts access to protected pages:
-
You read the token from storage.
-
Decode it to extract role/claims.
-
Use React Router +
PrivateRoute(or similar) to guard access.
-
🧱 How to Restrict Pages in React (Role-Based Routing)
✅ Step 1: Decode and Check the Token
npm install jwt-decode
import jwtDecode from "jwt-decode";
function getUserFromToken() {
const token = localStorage.getItem("token");
if (!token) return null;
try {
const decoded = jwtDecode(token);
return decoded; // contains roles, exp, username, etc.
} catch {
return null;
}
}
✅ Step 2: Create a Protected Route Component
import { Navigate } from "react-router-dom";
function PrivateRoute({ children, requiredRole }) {
const user = getUserFromToken();
if (!user) return <Navigate to="/login" />;
if (requiredRole && !user.role?.includes(requiredRole)) {
return <Navigate to="/unauthorized" />;
}
return children;
}
✅ Step 3: Use It in Routing
<Route
path="/admin-dashboard"
element={
<PrivateRoute requiredRole="Admin">
<AdminDashboard />
</PrivateRoute>
}
/>
🛡️ Where to Store the JWT?
| Method | Persistent? | Secure? | Notes |
|---|---|---|---|
localStorage |
✅ Yes | ❌ No (accessible to JS) | Good for simple apps |
sessionStorage |
❌ No (clears on tab close) | ❌ No | |
HttpOnly cookie |
✅ Yes | ✅ Yes | Needs backend to set cookie |
🔐 If your app is vulnerable to XSS, use
HttpOnlycookies instead of localStorage.
🧷 Automatically Adding JWT to Requests
You can use Axios interceptors:
// axios.js
import axios from "axios";
const api = axios.create({
baseURL: "http://your-api-url.com/api",
});
api.interceptors.request.use(config => {
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
export default api;
Then use api.get(...) or api.post(...) in your services.
🧠 Summary
| Task | Solution |
|---|---|
| Protect route to logged-in users | Use custom <PrivateRoute /> with token check |
| Check if user has a role | Decode token and inspect role claim |
| Send token with API requests | Use Axios interceptors |
| Save token | LocalStorage (easy) or HttpOnly cookie (secure) |
| Keep user logged in | Token stays in localStorage or cookie |
| Handle logout | Clear the token from storage |
Let me know if you want:
-
A sample React project with protected routes and JWT integration
-
How to implement auto-logout when token expires
-
How to use refresh tokens
Happy to walk you through any of it!
That flow is excellent and matches exactly how modern applications with JWT-based authentication typically work. You're thinking about both UX (popup forms) and proper backend coordination — that's a solid start.
✅ Your Flow — Reviewed & Annotated:
1. Account Sign-Up (Register)
Frontend (React): Sign-up modal with:
-
Phone number
-
Password (+ confirm password)
-
Basic validations (empty fields, password length, etc.)
Backend (ASP.NET Core API):
-
Validate: Check if phone already exists
-
Validate password strength (you can set rules)
-
Hash the password securely (use
PasswordHasher<T>or Identity's helper) -
Store the user in DB (with phone number as username or unique field)
-
Return success/failure
✅ Note: Use [ApiController], [FromBody], and model validation on the backend for clean error reporting.
2. Login Page (Popup)
Frontend (React):
-
Login modal with:
-
Phone number
-
Password
-
Backend:
-
Validate credentials
-
If valid, generate:
-
JWT (access token) — includes user ID and roles
-
(Optional) Refresh token
-
-
Return the JWT token to the frontend
✅ Token Payload Example:
{
"sub": "user_id_here",
"phone": "09xxxxxxxxx",
"role": "Customer",
"exp": 1234567890
}
✅ You’ll send this token to the frontend in the response.
3. Store the Token + Access Protected Page
Frontend:
-
Store the token (in
localStoragefor now) -
Use Axios to attach it on every request
-
Use a
PrivateRoutecomponent to guard protected pages -
Access
/profilepage (protected by[Authorize]in backend)
Backend:
-
Secure
/profilewith[Authorize(Roles = "Customer")]or similar -
Parse token from
Authorization: Bearer <token>header -
Allow or reject based on claims
🛠️ What You'll Need
Frontend:
-
react-router-dom -
axios -
jwt-decode -
Modals (e.g., using Tailwind or a component lib)
Backend:
-
ASP.NET Core API (you already have it)
-
JWT configuration in
Program.cs -
Custom authentication controller (
/api/auth/register,/api/auth/login) -
Role support
-
Token generation utility
🚀 Ready to Begin?
Let's start with Step 1: Sign-up flow
Would you like to begin with:
-
Backend first — setting up
/api/auth/registerendpoint and phone+password validation -
Frontend first — creating the sign-up modal form in React
Let me know your preference and we’ll go step by step.