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

6.3 KiB
Raw Blame History

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:

      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

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 HttpOnly cookies 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
}

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.