786 lines
19 KiB
Markdown
786 lines
19 KiB
Markdown
|
||
# AUTHENTICATION METHODS FOR ASP.NET CORE WEB API
|
||
|
||
### 1. **JWT (JSON Web Token) Authentication**
|
||
|
||
**Most common for SPAs (like your React frontend)**
|
||
|
||
- ✅ **Stateless**: No session stored on the server.
|
||
|
||
- 🔐 **Token structure**: Header + Payload (including roles) + Signature.
|
||
|
||
- 🎯 Good for: SPAs, mobile apps, APIs.
|
||
|
||
- 📦 Libraries: `Microsoft.AspNetCore.Authentication.JwtBearer`.
|
||
|
||
|
||
**Setup Highlights:**
|
||
|
||
- Client sends credentials → API generates token with user roles → Client stores token → Client sends token in `Authorization` header (`Bearer <token>`).
|
||
|
||
- Server verifies signature and extracts user identity and roles from the token.
|
||
|
||
|
||
**Role support**:
|
||
|
||
- You embed roles inside the JWT (`"roles": ["Admin", "User"]`).
|
||
|
||
- Use `[Authorize(Roles = "Admin")]`.
|
||
|
||
|
||
---
|
||
|
||
### 2. **Cookie-Based Authentication**
|
||
|
||
**Traditional approach for server-rendered apps (not ideal for APIs)**
|
||
|
||
- 🛑 **Not recommended for APIs** due to CSRF vulnerability and session overhead.
|
||
|
||
- 🗂 Stores session identifier in browser cookie.
|
||
|
||
- Useful when using ASP.NET Core MVC or Razor Pages (not Web API).
|
||
|
||
|
||
---
|
||
|
||
### 3. **OAuth2 + OpenID Connect (OIDC)**
|
||
|
||
**Best for federated login, single sign-on (SSO), or external providers**
|
||
|
||
- 🔗 Integrates with Identity Providers (IDPs) like:
|
||
|
||
- Azure AD
|
||
|
||
- Google, Facebook, GitHub
|
||
|
||
- Auth0, Okta, Duende IdentityServer
|
||
|
||
- 📦 Library: `Microsoft.AspNetCore.Authentication.OpenIdConnect`
|
||
|
||
- Uses **access tokens** (JWT) issued by an authority.
|
||
|
||
|
||
**Role support**:
|
||
|
||
- Roles/claims provided by the Identity Provider.
|
||
|
||
- You map these claims to roles in the API.
|
||
|
||
- `[Authorize(Roles = "Admin")]` still works.
|
||
|
||
|
||
---
|
||
|
||
### 4. **API Key Authentication**
|
||
|
||
**Lightweight alternative (not ideal for user-based roles)**
|
||
|
||
- Client includes a static API key in headers or query string.
|
||
|
||
- 🔐 No user context → ❌ no role-based support unless you map API keys to roles in a custom way.
|
||
|
||
- 🔧 Implemented manually in middleware or filters.
|
||
|
||
|
||
---
|
||
|
||
### 5. **Basic Authentication**
|
||
|
||
- User provides `username:password` in Base64 via `Authorization` header.
|
||
|
||
- ❌ Insecure unless used with HTTPS.
|
||
|
||
- ⚠️ Rarely used anymore — not good for role-based systems or production apps.
|
||
|
||
|
||
---
|
||
|
||
### 6. **ASP.NET Core Identity**
|
||
|
||
**Full-featured user management system (often combined with JWT)**
|
||
|
||
- ✅ Provides login, registration, role management, password hashing, etc.
|
||
|
||
- 🎯 Good choice if you want to **own the user system** and **manage roles** yourself.
|
||
|
||
- Can be used with:
|
||
|
||
- JWT tokens (custom token generation)
|
||
|
||
- Cookie auth (not for APIs)
|
||
|
||
- 🔧 Use `UserManager`, `RoleManager`.
|
||
|
||
|
||
**Example**: Use Identity for creating users and roles, then issue JWTs on login.
|
||
|
||
---
|
||
|
||
|
||
## Summary Table
|
||
|
||
|Method|Stateless|Token-Based|Role Support|Ideal For|
|
||
|---|---|---|---|---|
|
||
|JWT Authentication|✅|✅|✅|APIs, SPAs (React, etc.)|
|
||
|Cookie Authentication|❌|❌|✅|Server-side apps only|
|
||
|OAuth2 + OpenID Connect|✅|✅|✅|External login, SSO, enterprise|
|
||
|API Key|✅|❌|❌ (manual)|Simple apps, service-to-service|
|
||
|Basic Auth|✅|❌|❌ (manual)|Very basic use, not recommended|
|
||
|ASP.NET Core Identity|❌|Optional|✅|User/Role management|
|
||
|
||
---
|
||
|
||
# Web Security and JWT Terms
|
||
|
||
|
||
### 🧨 **CSP (Content Security Policy)**
|
||
|
||
**Definition:**
|
||
A **browser security mechanism** that helps prevent **XSS attacks** by controlling which sources the browser can load content from.
|
||
|
||
**Example Usage:**
|
||
It can prevent JavaScript from running unless it's from a trusted source.
|
||
|
||
**Example CSP header:**
|
||
|
||
```http
|
||
Content-Security-Policy: default-src 'self'; script-src 'self' https://trustedscripts.example.com
|
||
```
|
||
|
||
---
|
||
|
||
### 💥 **XSS (Cross-Site Scripting)**
|
||
|
||
**Definition:**
|
||
A vulnerability where an attacker **injects malicious JavaScript** into a web page that gets executed in a user’s browser.
|
||
|
||
**Why It Matters for JWT:**
|
||
If you store JWTs in `localStorage`, and your app is vulnerable to XSS, the attacker can steal the token and impersonate the user.
|
||
|
||
**Prevention:**
|
||
|
||
- Never trust user input (sanitize!)
|
||
|
||
- Use **CSP headers**
|
||
|
||
- Avoid inline scripts
|
||
|
||
- Use frameworks that auto-escape HTML (like React, Razor)
|
||
|
||
|
||
---
|
||
|
||
### 📦 **Payload (in JWT)**
|
||
|
||
**Definition:**
|
||
The **middle part** of a JWT. It contains the **claims** (user data, permissions, roles, etc.) in a **Base64-encoded JSON** format.
|
||
|
||
**Example:**
|
||
|
||
```json
|
||
{
|
||
"sub": "1234567890",
|
||
"name": "John Doe",
|
||
"role": "Admin",
|
||
"exp": 1716850984
|
||
}
|
||
```
|
||
|
||
⚠️ **Note:** Payload is **not encrypted**, just encoded — anyone can read it, but not modify it without invalidating the signature.
|
||
|
||
---
|
||
|
||
### ✍️ **Signature (in JWT)**
|
||
|
||
**Definition:**
|
||
The **third part** of the token. It's a cryptographic hash (HMAC or RSA/ECDSA) of the header and payload, signed with a **secret** or private key.
|
||
|
||
**Purpose:**
|
||
To verify that the token **hasn’t been tampered with**.
|
||
|
||
**Structure:**
|
||
|
||
```
|
||
JWT = base64(header) + '.' + base64(payload) + '.' + signature
|
||
```
|
||
|
||
Only the server (with the secret key) can validate the signature.
|
||
|
||
---
|
||
|
||
### 🦠 **CSRF (Cross-Site Request Forgery)**
|
||
|
||
**Definition:**
|
||
A vulnerability where an attacker tricks a user’s **browser** (with a valid session/cookie) into making an unwanted request to your site **without the user’s knowledge**.
|
||
|
||
**Example:**
|
||
If you're logged in and visit a malicious site, that site may submit a POST request using your cookies to perform actions on your behalf.
|
||
|
||
**Why It Matters:**
|
||
|
||
- If you store JWTs in **HttpOnly cookies**, you must guard against CSRF.
|
||
|
||
|
||
**Defense:**
|
||
|
||
- Use `SameSite=Strict` cookies
|
||
|
||
- Use anti-CSRF tokens
|
||
|
||
- Prefer `Authorization` header with tokens (doesn’t auto-send like cookies)
|
||
|
||
|
||
---
|
||
|
||
### 🧠 **Session Overhead**
|
||
|
||
**Definition:**
|
||
The **memory and server resource cost** of maintaining a session for each logged-in user on the server.
|
||
|
||
**Why It Matters:**
|
||
|
||
- Traditional **cookie-based auth** stores session info on the server.
|
||
|
||
- With JWT, the session is **stateless** (no server memory), reducing overhead and scaling better.
|
||
|
||
|
||
---
|
||
|
||
## 🔑 **Authentication Ecosystem Concepts**
|
||
|
||
---
|
||
|
||
### 🌐 **Federated Login**
|
||
|
||
**Definition:**
|
||
Users log in to your application using **another trusted identity provider** (IdP), such as:
|
||
|
||
- Google
|
||
|
||
- Facebook
|
||
|
||
- Microsoft
|
||
|
||
- GitHub
|
||
|
||
|
||
You delegate authentication to the third party and just receive user info (often as a JWT or OpenID Connect token).
|
||
|
||
**Protocol Examples:**
|
||
|
||
- OAuth2
|
||
|
||
- OpenID Connect
|
||
|
||
|
||
---
|
||
|
||
### 🔁 **SSO (Single Sign-On)**
|
||
|
||
**Definition:**
|
||
A user logs in **once** and gains access to **multiple systems or applications** without logging in again.
|
||
|
||
**Common in Enterprises**:
|
||
|
||
- Logging into one dashboard gives you access to HR system, email, file storage, etc.
|
||
|
||
|
||
**How It Works:**
|
||
|
||
- A **central identity provider (IdP)** issues tokens
|
||
|
||
- Applications **trust the token** and skip login
|
||
|
||
- Often uses **OAuth2**, **OpenID Connect**, or **SAML**
|
||
|
||
|
||
---
|
||
|
||
## 🔄 Summary Table
|
||
|
||
|Term|Meaning|
|
||
|---|---|
|
||
|**CSP**|Restricts sources of scripts/styles to prevent XSS|
|
||
|**XSS**|Injected JavaScript that steals data like JWT tokens|
|
||
|**JWT Payload**|JSON with user claims (readable but not secure on its own)|
|
||
|**JWT Signature**|Proves the token is untampered (signed by server)|
|
||
|**CSRF**|Unauthorized actions using authenticated user's browser/session|
|
||
|**Session Overhead**|Cost of storing user sessions in memory on the server|
|
||
|**Federated Login**|Login using a third-party identity provider (e.g., Google)|
|
||
|**SSO**|One login grants access to multiple trusted systems|
|
||
|
||
|
||
# ASP.NET Identity vs JWT Authentication
|
||
|
||
---
|
||
|
||
### ✅ **What is ASP.NET Identity?**
|
||
|
||
**ASP.NET Identity** is a full **membership system** that:
|
||
|
||
- Manages users, roles, passwords, claims, tokens, and external logins.
|
||
|
||
- Stores user data in a **database** (usually using Entity Framework).
|
||
|
||
- Works well with **cookie-based authentication** by default.
|
||
|
||
- Handles login, logout, registration, password hashing, email confirmation, two-factor auth, etc.
|
||
|
||
|
||
**Default storage:** SQL Server (via Entity Framework)
|
||
|
||
---
|
||
|
||
### 🔑 **How Authentication Works in ASP.NET Identity (Cookie-Based)**
|
||
|
||
1. **Login request**: The user submits a form with username/password.
|
||
|
||
2. **Server validates** the credentials using ASP.NET Identity.
|
||
|
||
3. If valid, the server issues a **cookie** (with a session token).
|
||
|
||
4. The browser stores this **authentication cookie**.
|
||
|
||
5. For future requests, the browser **automatically sends the cookie**.
|
||
|
||
6. The server validates the cookie (and reads the user session from memory or database).
|
||
|
||
|
||
✅ **Stateful**
|
||
❌ Doesn't scale well for large APIs unless you add external session storage (like Redis).
|
||
|
||
---
|
||
|
||
### 🔐 What is JWT Authentication?
|
||
|
||
JWT Authentication is:
|
||
|
||
- **Stateless**.
|
||
|
||
- Based on tokens — not sessions.
|
||
|
||
- Works well for APIs and SPAs/mobile apps.
|
||
|
||
|
||
#### Flow:
|
||
|
||
1. **User logs in**, and if credentials are valid...
|
||
|
||
2. Server **creates a JWT** containing user info (e.g., roles).
|
||
|
||
3. Server **signs the token** and sends it to the client.
|
||
|
||
4. Client stores it (e.g., in localStorage or cookies).
|
||
|
||
5. On every request, the client sends the JWT in the `Authorization` header.
|
||
|
||
6. Server **verifies the JWT signature** using a secret or key.
|
||
|
||
7. If valid → allow access (no server-side session needed).
|
||
|
||
|
||
✅ **Stateless**
|
||
✅ Scales easily
|
||
✅ Good for distributed APIs
|
||
|
||
---
|
||
|
||
### 📊 Comparison Table
|
||
|
||
|Feature|ASP.NET Identity (Cookie)|JWT Authentication (Token-Based)|
|
||
|---|---|---|
|
||
|**Stateful/Stateless**|Stateful|Stateless|
|
||
|**Storage**|Cookie on client, session on server|Token on client only|
|
||
|**Default Transport**|Cookie (auto-sent by browser)|Authorization header (manual send)|
|
||
|**Built-in Support**|ASP.NET Identity (UI + EF Core)|ASP.NET Core + Manual JWT setup|
|
||
|**Scalability**|Limited (server stores session)|High (no session to manage)|
|
||
|**Security**|Cookie CSRF risk|XSS risk if stored in JS-accessible storage|
|
||
|**Use Case**|Web apps with UI (MVC, Razor)|APIs, SPAs, mobile apps|
|
||
|**External login support**|Built-in|Needs integration|
|
||
|**Token expiration**|Server-controlled session|Token has expiration embedded|
|
||
|
||
---
|
||
|
||
### 🚨 Statelessness — What Does It Mean?
|
||
|
||
- **Stateful Authentication**: Server **stores a session** (usually in memory or a database) for each user. The client just stores a cookie with a session ID.
|
||
|
||
- When user logs in, server keeps a record of that.
|
||
|
||
- Logout → delete session.
|
||
|
||
- **Stateless Authentication** (JWT):
|
||
|
||
- Server **does not remember anything**.
|
||
|
||
- JWT has all info about the user in itself (claims, roles, expiry).
|
||
|
||
- Logout = just delete token on client side (server has no "memory").
|
||
|
||
|
||
⚠️ **You can't "force logout" someone server-side in pure JWT unless you blacklist tokens manually** (or rotate secrets).
|
||
|
||
---
|
||
|
||
### 💡 Can You Use ASP.NET Identity with JWT?
|
||
|
||
Yes — ASP.NET Identity can be configured to:
|
||
|
||
- Authenticate user credentials
|
||
|
||
- Then issue a **JWT** instead of using a cookie
|
||
|
||
- This way, you get:
|
||
|
||
- ASP.NET Identity’s user management
|
||
|
||
- JWT’s **stateless** API authentication
|
||
|
||
|
||
This is often used in **hybrid apps**:
|
||
|
||
- Use Identity for registration/login
|
||
|
||
- Use JWT for frontend and mobile API calls
|
||
|
||
|
||
|
||
# What does `null!` mean?
|
||
|
||
It's a **null-forgiving operator**.
|
||
|
||
When you write:
|
||
|
||
```csharp
|
||
string? maybeNull = null;
|
||
string definitelyNotNull = null!; // ← This tells the compiler: “Trust me, it’s not null.”
|
||
```
|
||
|
||
You're telling the compiler:
|
||
|
||
> _“I know this is technically null, but treat it as non-null and don’t warn me.”_
|
||
|
||
---
|
||
|
||
### 🧩 Why is this needed?
|
||
|
||
C# 8 introduced **nullable reference types**, where the compiler gives warnings if you assign or use `null` where it's not safe.
|
||
|
||
For example:
|
||
|
||
```csharp
|
||
string name = null; // Warning: assigning null to non-nullable reference
|
||
```
|
||
|
||
To silence the warning, you can use `null!`:
|
||
|
||
```csharp
|
||
string name = null!; // No warning
|
||
```
|
||
|
||
But this is **your responsibility**: the compiler **assumes you're guaranteeing** that it won’t cause a `NullReferenceException`.
|
||
|
||
---
|
||
|
||
### ⚠️ When to use `null!`?
|
||
|
||
Use it **sparingly and carefully**, only when:
|
||
|
||
- You know an object **will be initialized later**.
|
||
|
||
- You’re working with **ORMs like EF Core** where properties are set **after construction**.
|
||
|
||
- You're dealing with **dependency injection** and the value is assigned **automatically later**.
|
||
|
||
|
||
#### Example:
|
||
|
||
```csharp
|
||
public class Account
|
||
{
|
||
public string PhoneNumber { get; set; } = null!; // EF will populate it
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### ✅ Summary
|
||
|
||
|Expression|Meaning|
|
||
|---|---|
|
||
|`null!`|"This is null, but treat it as if it's non-null (trust me)."|
|
||
|Use case|Avoiding compiler warnings for nullable reference types|
|
||
|Risk|Can lead to runtime `NullReferenceException` if used incorrectly|
|
||
|
||
---
|
||
|
||
Let me know if you want help turning on/off nullable reference types or dealing with EF Core model warnings.
|
||
|
||
|
||
# What is a JWT Generator?
|
||
|
||
A **JWT Generator** is a class or service in your backend that:
|
||
|
||
1. **Generates** a signed JWT (JSON Web Token) when a user logs in.
|
||
|
||
2. **Encodes** the user's identity, roles, and other claims.
|
||
|
||
3. **Signs** the token with a secret or private key so it can be validated later.
|
||
|
||
|
||
---
|
||
|
||
## 🔧 Structure of a JWT
|
||
|
||
A JWT has 3 parts:
|
||
|
||
```plaintext
|
||
xxxxx.yyyyy.zzzzz
|
||
```
|
||
|
||
1. **Header** (Base64-encoded JSON):
|
||
|
||
```json
|
||
{
|
||
"alg": "HS256",
|
||
"typ": "JWT"
|
||
}
|
||
```
|
||
|
||
2. **Payload** (Base64-encoded JSON):
|
||
Contains user data and claims (e.g., user ID, role, expiry).
|
||
|
||
```json
|
||
{
|
||
"sub": "userId123",
|
||
"phone": "0930xxx",
|
||
"role": "Admin",
|
||
"exp": 1717502800
|
||
}
|
||
```
|
||
|
||
3. **Signature**:
|
||
HMACSHA256(header + "." + payload, secret key)
|
||
|
||
|
||
---
|
||
|
||
## ✅ What Goes into the Payload?
|
||
|
||
Include things you want to check _without querying the DB every time_:
|
||
|
||
- `sub` (Subject – usually user ID)
|
||
|
||
- `phone` or username
|
||
|
||
- `role` (e.g., "Admin", "User")
|
||
|
||
- `exp` (expiration timestamp)
|
||
|
||
- Any custom claim, like `companyId`, `verified`, etc.
|
||
|
||
|
||
---
|
||
|
||
## 🔐 Signature
|
||
|
||
The **signature ensures** that the token hasn't been tampered with. If the signature doesn't match (due to modification or incorrect secret), the token is invalid.
|
||
|
||
---
|
||
|
||
## 🧱 Example: JWT Generator in ASP.NET Core
|
||
|
||
```csharp
|
||
public interface IJwtGenerator
|
||
{
|
||
string GenerateToken(Account account);
|
||
}
|
||
```
|
||
|
||
```csharp
|
||
public class JwtGenerator : IJwtGenerator
|
||
{
|
||
private readonly IConfiguration _config;
|
||
|
||
public JwtGenerator(IConfiguration config)
|
||
{
|
||
_config = config;
|
||
}
|
||
|
||
public string GenerateToken(Account account)
|
||
{
|
||
var claims = new[]
|
||
{
|
||
new Claim(JwtRegisteredClaimNames.Sub, account.Id.ToString()),
|
||
new Claim(JwtRegisteredClaimNames.PhoneNumber, account.PhoneNumber),
|
||
new Claim(ClaimTypes.Role, account.Role),
|
||
};
|
||
|
||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]!));
|
||
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||
|
||
var token = new JwtSecurityToken(
|
||
issuer: _config["Jwt:Issuer"],
|
||
audience: _config["Jwt:Audience"],
|
||
claims: claims,
|
||
expires: DateTime.UtcNow.AddHours(2),
|
||
signingCredentials: creds
|
||
);
|
||
|
||
return new JwtSecurityTokenHandler().WriteToken(token);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🛠 Configuration in `appsettings.json`
|
||
|
||
```json
|
||
"Jwt": {
|
||
"Key": "YourSuperSecureSecretKey123!",
|
||
"Issuer": "YourAppName",
|
||
"Audience": "YourFrontendApp"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🧪 Token Validation
|
||
|
||
When the frontend sends this token on requests (via `Authorization: Bearer <token>` header), ASP.NET Core automatically validates:
|
||
|
||
- Signature (using the same secret)
|
||
|
||
- Expiry (`exp`)
|
||
|
||
- Audience, Issuer
|
||
|
||
- Claims (like role)
|
||
|
||
|
||
This is done via `JwtBearer` middleware.
|
||
|
||
---
|
||
|
||
## 🔐 Roles in the Token?
|
||
|
||
Yes, you can (and should) include user roles. The backend will **automatically enforce** `[Authorize(Roles = "Admin")]` using that claim.
|
||
|
||
But:
|
||
|
||
- Don't rely **only** on frontend logic — always **protect endpoints** on the backend too.
|
||
|
||
- Frontend can use roles to **hide UI elements**, but not for enforcing access.
|
||
|
||
|
||
---
|
||
|
||
## 🤔 Should You Encrypt the Token?
|
||
|
||
No, standard practice is:
|
||
|
||
- Don't encrypt JWTs — they’re just base64-encoded.
|
||
|
||
- **Don’t put sensitive data** inside.
|
||
|
||
- Sign them to prevent tampering.
|
||
|
||
- Secure the token in frontend (e.g., HttpOnly cookies or `localStorage` with care).
|
||
|
||
|
||
---
|
||
|
||
## ✅ Summary of Responsibilities
|
||
|
||
|Responsibility|Backend (JWT Generator)|Frontend|
|
||
|---|---|---|
|
||
|Token generation|✅|❌|
|
||
|Storing token|❌|✅ (localStorage / cookie)|
|
||
|Sending token|❌|✅ (Authorization header)|
|
||
|Token validation|✅ (`JwtBearer`)|❌|
|
||
|Role enforcement|✅ (`[Authorize]`)|✅ (UI-level only)|
|
||
|
||
|
||
|
||
---
|
||
|
||
# How multiple roles in JWT claims work
|
||
|
||
- The JWT claims are basically a list of key-value pairs.
|
||
|
||
- For roles, the key is usually `"role"` or `ClaimTypes.Role`.
|
||
|
||
- You add **multiple claims with the same key** — one for each role.
|
||
|
||
|
||
**Example:**
|
||
|
||
```json
|
||
{
|
||
"sub": "1234567890",
|
||
"phone_number": "123456789",
|
||
"role": "Admin",
|
||
"role": "Editor",
|
||
"role": "User",
|
||
"exp": 1711600000
|
||
}
|
||
```
|
||
|
||
- When the token is created, it contains multiple `"role"` entries.
|
||
|
||
- On the backend, ASP.NET Core `ClaimsPrincipal` reads all of them, so `[Authorize(Roles="Admin,Editor")]` works by checking if **any** of the roles match.
|
||
|
||
|
||
---
|
||
|
||
### How frontend handles multiple roles in the JWT
|
||
|
||
1. The frontend receives the JWT (usually after login).
|
||
|
||
2. It **decodes** the JWT payload (using a library like `jwt-decode`).
|
||
|
||
3. It extracts the roles as an **array of strings**.
|
||
|
||
|
||
Example in React using `jwt-decode`:
|
||
|
||
```js
|
||
import jwtDecode from 'jwt-decode';
|
||
|
||
const token = localStorage.getItem('token');
|
||
const decoded = jwtDecode(token);
|
||
const roles = decoded.role; // roles is usually an array if multiple roles exist
|
||
|
||
console.log(roles); // ["Admin", "Editor", "User"]
|
||
```
|
||
|
||
4. The frontend can then use these roles to:
|
||
|
||
- Conditionally render UI components or routes.
|
||
|
||
- Show/hide buttons, pages, or features.
|
||
|
||
|
||
---
|
||
|
||
### Important security note for frontend roles
|
||
|
||
- The frontend can **only do UI-level checks** based on roles.
|
||
|
||
- **Never trust frontend role checks to secure data or APIs.**
|
||
|
||
- The backend must always verify the token and roles via `[Authorize]` attributes or middleware.
|
||
|
||
|
||
---
|
||
|
||
### Summary
|
||
|
||
| Step | How it works |
|
||
| --------------------- | ----------------------------------------------------- |
|
||
| JWT creation | Multiple `"role"` claims added to token |
|
||
| Backend authorization | Validates token and checks if user has required roles |
|
||
| Frontend decoding | Extracts `role` claim(s) as array of strings |
|
||
| Frontend UI control | Shows or hides content based on roles |
|