Skip to content

Authentication

Full Stack edited this page Aug 13, 2025 · 8 revisions

Types of authentication

read image

[1.] 𝐀𝐏𝐈 𝐊𝐞𝐲𝐬 ◾ Simple, unique identifiers assigned to each client or service. ◾ Sent as a header or query parameter with each request. ◾ Best suited for internal services, less sensitive APIs, or for granting access to specific features. ◾ Easy to implement and manage. ◾ Not as secure as token-based methods. Keys can be easily leaked or stolen.

[2.] 𝐁𝐚𝐬𝐢𝐜 𝐀𝐮𝐭𝐡𝐞𝐧𝐭𝐢𝐜𝐚𝐭𝐢𝐨𝐧 ◾ Username and password are sent in the Authorization header as base64 encoded string. ◾ Simple to implement but requires HTTPS to be secure. ◾ Suitable for simple scenarios with low-security requirements. ◾ Widely supported and easy to understand. ◾ Vulnerable to man-in-the-middle attacks if not used with HTTPS. ◾ Passwords are sent in cleartext (even when encoded).

[3.] 𝐉𝐒𝐎𝐍 𝐖𝐞𝐛 𝐓𝐨𝐤𝐞𝐧𝐬 (𝐉𝐖𝐓) ◾ Self-contained tokens that carry user information and claims in a JSON payload. ◾ Issued by an authentication server after successful login, then sent by the client in the Authorization header. ◾ Widely used for stateless authentication in microservices, single sign-on (SSO) and authorization. ◾ Stateless, secure, compact and can contain additional claims. ◾ Requires proper key management for signing and verification.

[4.] 𝐎𝐀𝐮𝐭𝐡 2.0 ◾ An authorization framework allowing third-party applications to obtain limited access to resources on behalf of the resource owner (user) without sharing credentials. ◾ Uses various grant types (authorization code, implicit, client credentials, etc.) to obtain access tokens and refresh tokens. ◾ Widely used for user authorization and delegated access to APIs. ◾ Provides a standardized way to secure access to resources without sharing credentials. ◾ Can be complex to implement and requires careful consideration of security vulnerabilities.

[5.] 𝐎𝐩𝐞𝐧𝐈𝐃 𝐂𝐨𝐧𝐧𝐞𝐜𝐭 (𝐎𝐈𝐃𝐂) ◾ An identity layer on top of OAuth 2.0 that provides user authentication and profile information. ◾ Uses an ID token along with the access token to provide user identity information. ◾ Used for authentication in conjunction with OAuth 2.0 for authorization. ◾ Simplifies authentication by providing a standardized way to obtain user information. ◾ Requires integration with an OIDC provider (e.g., Google, Okta).

[6.] 𝐌𝐮𝐭𝐮𝐚𝐥 𝐓𝐋𝐒 (𝐦𝐓𝐋𝐒) ◾ Both client and server authenticate each other using X.509 certificates. ◾ Requires a certificate authority (CA) to issue and manage certificates. ◾ Best suited for securing communication between internal services or highly sensitive APIs. ◾ Strong security due to mutual authentication and encryption. ◾ More complex to set up and manage compared to other mechanisms.

JWT

JWT or JSON Web Tokens is an open standard for securely transmitting information between two parties. They are widely used for authentication and authorization.

A JWT consists of three main components:

1 - Header Every JWT carries a header specifying the algorithms for signing the JWT. It’s written in JSON format.

2 - Payload The payload consists of the claims and the user data. There are different types of claims such as registered, public, and private claims.

3 - Signature The signature is what makes the JWT secure. It is created by taking the encoded header, encoded payload, secret key, and the algorithm and signing it.

JWTs can be signed in two different ways:

1 - Symmetric Signatures It uses a single secret key for both signing the token and verifying it. The same key must be shared between the server that signs the JWT and the system that verifies it.

2 - Asymmetric Signatures In this case, a private key is used to sign the token, and a public key to verify it. The private key is kept secure on the server, while the public key can be distributed to anyone who needs to verify the token.

image
SAML vs OpenID Connect

🔑 Key Differences Between SAML and OIDC

Feature SAML (Security Assertion Markup Language) OIDC (OpenID Connect)
Protocol Type XML-based SSO authentication protocol JSON-based authentication layer over OAuth2
Underlying Standard Uses XML (Extensible Markup Language) Uses JSON (JavaScript Object Notation)
Authentication vs Authorization Primarily for authentication Used for authentication but built on OAuth2 (authorization)
Transport Mechanism Relies on HTTP POST (via browser redirects) Uses RESTful API calls (via tokens in HTTP headers)
Tokens Used SAML Assertions (XML format) JWT (JSON Web Token)
Best Suited For Enterprise apps, SSO for internal/corporate networks Web & mobile apps, APIs, microservices
IdP Communication Uses Service Provider (SP) & Identity Provider (IdP) Uses Client, Authorization Server, and Resource Server
Token Storage SAML Assertion is not stored; it is a one-time authentication response JWT is stored in the app (local storage, cookies) for re-authentication
Session Management Server-side (stateless) Can be both stateful or stateless
Mobile App Support Not ideal for mobile apps Designed for mobile-friendly authentication
Scalability Heavier due to XML parsing Lightweight & faster due to JSON
Use Cases Enterprise SSO (Okta, AD FS, PingFederate) Web, API authentication (Google, Microsoft, AWS Cognito)

📌 When to Use SAML vs. OIDC?

  • Use SAML when:

    • You need Single Sign-On (SSO) for corporate/enterprise applications.
    • Your organization already uses Active Directory Federation Services (AD FS), Okta, or PingFederate.
    • You're dealing with legacy applications that rely on XML-based authentication.
  • Use OIDC when:

    • You are building a modern web or mobile application.
    • You need an API-driven authentication system (e.g., microservices, REST APIs).
    • You want a lightweight, JSON-based protocol with better support for mobile and cloud-based applications.

🚀 Summary

  • SAML is better for enterprise SSO with existing identity providers.
  • OIDC is better for modern applications that need API-driven authentication.
  • OIDC is more flexible, scalable, and mobile-friendly than SAML.

Would you like help implementing OIDC authentication in your .NET API? 🚀

Session based Vs JWT based

Think of session-based authentication like a boarding pass ID at an airport. The system keeps the details about your session in a secure store, and you’re given a session ID to use.

How It Works:

  1. The user logs in, and their credentials are validated by the server.
  2. The server creates a session with all user details and stores it in a session store (database or memory).
  3. A session ID is sent back to the client as a cookie.
  4. On every subsequent request, the browser sends the session ID cookie to the server.
  5. The server checks the session store for the ID to verify the user.

Pros:

  • Easy to invalidate sessions (just remove them from the store).
  • Familiar and simple for server-side apps.

Cons:

  • Not ideal for distributed systems (requires shared session storage).
  • Can become a bottleneck as the user base grows.

Imagine JWTs as your boarding pass with all flight details printed on it, but encrypted and signed. The server doesn’t need to store anything because the token itself holds all necessary data.

How It Works:

  1. The user logs in, and their credentials are validated by the server.
  2. The server generates a JWT containing user data (e.g., user ID, roles) and signs it with a secret key.
  3. The JWT is sent back to the client as a cookie or header.
  4. On subsequent requests, the browser sends the JWT.
  5. The server verifies the JWT using the secret key and extracts user data.

Pros:

  • Stateless: No server-side storage required.
  • Ideal for distributed systems and scaling.
  • Works well with microservices and client-side rendering.

Cons:

  • Revoking JWTs is difficult (you can’t just delete them).
  • Tokens can become stale if user permissions or roles change.
  • Larger payloads can slow down requests.

Session vs. JWTs: When to Use What?

Session-Based Authentication:

  • Centralized server architecture.
  • Easier to manage for small to medium-scale projects.
  • Applications where sessions need to be invalidated quickly (e.g., financial apps).

JWT-Based Authentication:

  • Distributed systems or microservices architecture.
  • When scalability is a priority.
  • Applications with APIs accessed by multiple clients (e.g., mobile and web apps).

Implementing Keycloak in a .NET 9 API Solution

read

🔐 Implementing Keycloak in a .NET 9 API Solution

Keycloak is an open-source Identity Provider (IdP) supporting OAuth2, OpenID Connect (OIDC), and SAML. Below are the steps to integrate Keycloak authentication into your .NET 9 API.


🛠️ Step 1: Run Keycloak Locally

First, you need to run Keycloak on your machine.

Option 1: Run Keycloak with Docker

docker run -p 8080:8080 \
  -e KEYCLOAK_ADMIN=admin \
  -e KEYCLOAK_ADMIN_PASSWORD=admin \
  quay.io/keycloak/keycloak start-dev

Option 2: Manual Installation

  1. Download Keycloak from: https://www.keycloak.org/downloads
  2. Extract and navigate to the Keycloak folder.
  3. Start Keycloak in development mode:
    bin/kc.sh start-dev

🛠️ Step 2: Create a Realm & Client in Keycloak

Now, configure Keycloak:

1️⃣ Login to Keycloak

2️⃣ Create a Realm

  • Click "Create Realm" → Enter "MyRealm" → Save.

3️⃣ Create a Client for .NET API

  • Go to "Clients" → Create a new client.
  • Client ID: "my-dotnet-api"
  • Client Type: "OpenID Connect"
  • Root URL: http://localhost:5000/ (Your API URL)
  • Save.

4️⃣ Configure Client Credentials

  • Under the "Credentials" tab, copy the Client Secret.
  • Under "Settings", enable:
    • "Client authentication" → ON
    • "Service accounts roles" → ON

5️⃣ Create a User

  • Go to "Users" → Click "Create".
  • Username: testuser
  • Email: test@example.com
  • Set Password: (Under the "Credentials" tab)

🛠️ Step 3: Configure .NET 9 API to Use Keycloak

Now, modify your .NET 9 API to support authentication.

1️⃣ Install Required Packages

Run the following command:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

2️⃣ Configure Authentication in Program.cs

Modify your Program.cs to use JWT Bearer Authentication:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;

var builder = WebApplication.CreateBuilder(args);

// Add Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = "http://localhost:8080/realms/MyRealm";
        options.Audience = "my-dotnet-api"; // Must match the Keycloak Client ID
        options.RequireHttpsMetadata = false; // Disable in development
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true
        };
    });

// Add Authorization
builder.Services.AddAuthorization();

var app = builder.Build();

app.UseAuthentication(); // Apply Authentication Middleware
app.UseAuthorization();

app.MapGet("/secure", () => "You are authenticated!")
    .RequireAuthorization(); // Protect this endpoint

app.Run();

🛠️ Step 4: Test Authentication

Now, test the authentication using Postman or cURL.

1️⃣ Get a Token from Keycloak

Using cURL

curl -X POST "http://localhost:8080/realms/MyRealm/protocol/openid-connect/token" \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "client_id=my-dotnet-api" \
     -d "grant_type=password" \
     -d "username=testuser" \
     -d "password=yourpassword"

Using Postman

  • POST: http://localhost:8080/realms/MyRealm/protocol/openid-connect/token
  • Body (x-www-form-urlencoded):
    • client_id=my-dotnet-api
    • grant_type=password
    • username=testuser
    • password=yourpassword

Response:

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_in": 300,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "Bearer"
}

🛠️ Step 5: Access a Protected API Endpoint

Now, call the secure API endpoint using the token.

curl -X GET "http://localhost:5000/secure" \
     -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

If the token is valid, you'll receive:

"You are authenticated!"

Otherwise, you'll get:

"401 Unauthorized"

🎯 Bonus: Role-Based Authorization

To restrict access based on roles, update Program.cs:

app.MapGet("/admin", () => "Welcome Admin!")
    .RequireAuthorization(policy => policy.RequireRole("admin"));

Then, assign the "admin" role to your Keycloak user.


📌 Summary

  1. Run Keycloak using Docker.
  2. Create a Realm & Client in Keycloak.
  3. Configure .NET API to authenticate using Keycloak.
  4. Obtain an Access Token and test authentication.
  5. Secure API Endpoints with role-based authorization.

🚀 Next Steps

  • ✅ Implement Role-Based Authorization.
  • ✅ Configure API Gateway Authentication.
  • ✅ Deploy Keycloak on Kubernetes for production.

Would you like help with Keycloak integration in Angular/React frontend? 🚀

Scope in Token based Authentication

read

Scope in Token Generation

In token-based authentication (such as OAuth 2.0 and OpenID Connect), scope is a mechanism for defining permissions or access levels that a client application has when requesting an access token.


Why is Scope Important?

  1. Restricts Access → Ensures tokens grant access to only specific resources, enhancing security.
  2. Minimizes Privileges → Implements least privilege by preventing over-permissioned tokens.
  3. Improves API Security → API endpoints check token scopes before granting access.
  4. Allows Granular Authorization → Different clients (e.g., mobile apps vs. web apps) can get different permissions.

How Scope Works in OAuth 2.0

  1. Client Requests a Token with Specific Scopes

    • Example request in OAuth 2.0:
    POST /oauth/token HTTP/1.1
    Host: authserver.com
    Content-Type: application/x-www-form-urlencoded
    

    grant_type=client_credentials &client_id=your_client_id &client_secret=your_client_secret &scope=read:users write:users

  2. Authorization Server Validates & Issues a Token with Granted Scopes

    • The Access Token contains allowed scopes (e.g., read:users).
  3. Resource Server (API) Checks the Scope

    • API endpoints validate whether the token has the required scope before allowing access.

Example of Scope Usage in a JWT Token

A JSON Web Token (JWT) with scopes might look like this:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1616882223,
  "exp": 1616885823,
  "scope": "read:users write:users"
}

Example: Enforcing Scope in C# ASP.NET Core

In ASP.NET Core, you can validate scopes using policy-based authorization.

Step 1: Add Authentication & Scope Policy in Program.cs

builder.Services.AddAuthentication("Bearer")
    .AddJwtBearer(options =>
    {
        options.Authority = "https://authserver.com";
        options.Audience = "my-api";
    });

builder.Services.AddAuthorization(options => { options.AddPolicy("ReadUsers", policy => policy.RequireClaim("scope", "read:users")); });


Step 2: Apply Scope to API Endpoints

[Authorize(Policy = "ReadUsers")]
[HttpGet("users")]
public IActionResult GetUsers()
{
    return Ok(new { message = "User data accessed!" });
}
  • If the token does not contain the read:users scope, access is denied (403 Forbidden).

Common Scope Examples

Scope Description
read:users Read user information
write:users Create/update users
delete:users Delete users
read:messages Read messages
write:messages Send messages

Key Takeaways

Scope defines what an access token can do (limits permissions).
APIs should enforce scope validation to enhance security.
Use policies in ASP.NET Core to check token claims.
Follow the principle of least privilege (don’t over-assign permissions).

Would you like a deeper dive into scope validation in an OAuth 2.0 provider like IdentityServer or Auth0? 🚀

Secure User Authentication with OIDC Authorization Code + PKCE on the Server (BFF)

read

Secure User Authentication with OIDC Authorization Code + PKCE on the Server (BFF)

Using the OpenID Connect (OIDC) Authorization Code Flow with Proof Key for Code Exchange (PKCE) in a Backend for Frontend (BFF) architecture is a highly recommended and secure approach for authenticating users in modern web and mobile applications.

What is it?

  • OpenID Connect (OIDC): Builds on top of OAuth 2.0 to provide an identity layer for authentication. It introduces ID tokens (JSON Web Tokens) for user identity and leverages the secure Authorization Code flow for token acquisition.

  • Proof Key for Code Exchange (PKCE): An extension to the Authorization Code Flow designed to protect against authorization code interception attacks, especially relevant for public clients (like SPAs and mobile apps) that cannot securely store a client secret.

  • Backend for Frontend (BFF): A dedicated backend service for each frontend client, responsible for handling OIDC authentication, managing tokens, and proxying API requests securely on the server-side.

How it works

  1. Frontend Initiates Login: The user clicks a login button in the frontend application.

  2. Frontend Redirects to BFF Login Endpoint: The frontend redirects the user's browser to a login endpoint hosted by the BFF.

  3. BFF Initiates OIDC Flow:

    • The BFF (acting as a confidential client) generates a code_verifier (a secret string) and derives a code_challenge from it.
    • The BFF redirects the user's browser to the Authorization Server (OpenID Provider), including the code_challenge in the request.
  4. User Authentication & Consent: The Authorization Server displays the login page, the user authenticates, and grants consent.

  5. Authorization Code Response: Upon successful authentication, the Authorization Server redirects the user's browser back to the BFF's callback endpoint with an authorization code.

  6. BFF Exchanges Code for Tokens:

    • The BFF receives the authorization code and makes a direct, back-channel request to the Authorization Server's token endpoint to exchange the code for an ID token, access token, and potentially a refresh token.
    • The BFF includes the code_verifier in this request.
    • The Authorization Server verifies the code_verifier against the stored code_challenge, preventing code interception attacks.
  7. BFF Establishes Session & Redirects: The BFF stores the tokens securely on the server, establishes a session for the user (often using an HttpOnly cookie), and redirects the user back to the frontend application.

  8. Frontend Accesses Resources: The frontend can now make requests to the BFF endpoints, and the BFF uses the stored tokens to proxy requests to the protected APIs, without exposing the tokens directly to the frontend.

Benefits of this approach

  • Enhanced Security: Protects against XSS and authorization code interception by keeping tokens off the browser and handling them securely on the server-side. Refresh tokens can also be managed safely by the backend.

  • Simplified Frontend: Authentication and token management logic is offloaded to the BFF, reducing frontend complexity.

  • Centralized Authentication: Authentication logic is managed in a single, secure location.

  • Improved User Experience: Tailored authentication flows can improve the user experience.

  • Flexibility & Scalability: The BFF pattern allows for optimization and independent scaling.

Conclusion

Combining OIDC Authorization Code + PKCE with a BFF architecture offers a secure and efficient way to handle user authentication by managing tokens and secrets on the server.

Clone this wiki locally