# 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 `). - 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 ` 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|