Files
ASP.NET/02_ProjectOrientedSessions/Session07/Session07 Frontend.md
T

304 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Great — now were connecting both ends of your application. Lets 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)
1. **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**).
2. **Frontend stores the token**:
- This is usually saved in:
- `localStorage` ✅ simple, persistent
- or an **HttpOnly cookie** ✅ safer, but needs server support
3. **Frontend sends the token on future API calls**:
- Automatically attaches the token as a header:
```js
Authorization: Bearer <token>
```
4. **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
```bash
npm install jwt-decode
```
```js
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
```jsx
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
```jsx
<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 `HttpOnly` cookies instead of localStorage**.
---
## 🧷 Automatically Adding JWT to Requests
You can use **Axios interceptors**:
```js
// 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**:
```json
{
"sub": "user_id_here",
"phone": "09xxxxxxxxx",
"role": "Customer",
"exp": 1234567890
}
```
✅ Youll send this token to the frontend in the response.
---
### **3. Store the Token + Access Protected Page**
> **Frontend**:
- Store the token (in `localStorage` for now)
- Use Axios to attach it on every request
- Use a `PrivateRoute` component to guard protected pages
- Access `/profile` page (protected by `[Authorize]` in backend)
> **Backend**:
- Secure `/profile` with `[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:
1. **Backend first** — setting up `/api/auth/register` endpoint and phone+password validation
2. **Frontend first** — creating the sign-up modal form in React
Let me know your preference and well go step by step.