Step-by-Step Process & Entities


Entities Involved

1. End User (Browser)

2. Blazor WebAssembly Application (Frontend)

3. MSAL.js Library

4. Microsoft Entra ID (CIAM Tenant)

5. ApiService (Backend API)


High-Level Authentication Flows

Flow 1: User Login & Authentication (Steps 1-7)

┌─────────────────────────────────────────────────────────────────┐
│              LOGIN & AUTHENTICATION FLOW (Steps 1-7)            │
└─────────────────────────────────────────────────────────────────┘

    ┌──────────────┐
    │   End User   │
    │   Browser    │
    └──────┬───────┘
           │
           │ Step 1: Navigate to app
           │ (https://partners-dev.test-egzynergy.com/)
           ▼
    ┌──────────────────────┐
    │  Blazor WebAssembly  │
    │  (Partner Portal)    │
    └──────┬───────────────┘
           │
           │ Step 2: Check sessionStorage
           │ No valid token found
           │ → Redirect to login
           ▼
    ┌──────────────────────────────┐
    │  Microsoft Entra ID (CIAM)   │
    │  Login Page                  │
    └──────┬───────────────────────┘
           │
           │ Step 3: User enters
           │ email + password + MFA
           ▼
    ┌──────────────────────────────┐
    │  Microsoft Entra ID          │
    │  Validates Credentials       │
    └──────┬───────────────────────┘
           │
           │ ✅ Valid credentials
           │
           │ Step 4: Returns
           │ authorization code
           ▼
    ┌──────────────────────┐
    │  MSAL.js Library     │
    │  (in browser)        │
    └──────┬───────────────┘
           │
           │ Step 5: Exchange code
           │ for tokens (PKCE)
           ▼
    ┌──────────────────────────────┐
    │  Microsoft Entra ID          │
    │  Token Endpoint              │
    └──────┬───────────────────────┘
           │
           │ Returns 3 tokens:
           │ • Access Token (1h)
           │ • Refresh Token (90d)
           │ • ID Token (1h)
           ▼
    ┌──────────────────────┐
    │  Browser             │
    │  sessionStorage      │
    └──────┬───────────────┘
           │
           │ Step 6: Tokens stored
           │ (indexed by scope)
           │
           │ Step 7: Redirect back
           │ to original page
           ▼
    ┌────────────────────────────────┐
    │   ✅ USER AUTHENTICATED         │
    │   Ready to use the app         │
    └────────────────────────────────┘

Flow 2: API Calls with Token Validation (Steps 8-9)

┌─────────────────────────────────────────────────────────────────┐
│            API CALL & VALIDATION FLOW (Steps 8-9)               │
└─────────────────────────────────────────────────────────────────┘

    ┌────────────────────────────────┐
    │   User interacts with app      │
    │   (e.g., views overview page)  │
    └────────────┬───────────────────┘
                 │
                 │ Step 8: Blazor makes API request
                 ▼
    ┌──────────────────────────────────┐
    │  ApiAuthenticationHandler        │
    │  (HTTP Message Handler)          │
    └──────┬───────────────────────────┘
           │
           │ Requests token from MSAL.js
           │ Scope: api://4dad5d62.../ApiService_UserAccess
           ▼
    ┌──────────────────────┐
    │  MSAL.js Library     │
    │  sessionStorage      │
    └──────┬───────────────┘
           │
           │ Returns access token
           │ (or refreshes if expired)
           ▼
    ┌──────────────────────────────┐
    │  HTTP Request                │
    │  GET /api/v1/WorkOrder/...   │
    │  Authorization: Bearer eyJ... │
    └──────┬───────────────────────┘
           │
           │ Step 9: Request received
           ▼
    ┌──────────────────────────────────┐
    │  ApiService                      │
    │  JWT Authentication Middleware   │
    └──────┬───────────────────────────┘
           │
           │ Token Validation:
           │ ✓ Signature (Azure AD keys)
           │ ✓ Issuer (CIAM tenant)
           │ ✓ Audience (this API)
           │ ✓ Expiration (not expired)
           │ ✓ Groups (authorization)
           │
           ├─── ✅ Valid ────┐    ❌ Invalid ───┐
           │                 │                   │
           ▼                 ▼                   ▼
    ┌──────────────┐  ┌──────────────┐  ┌──────────────┐
    │  Controller  │  │  200 OK      │  │  401/403     │
    │  Processes   │  │  Returns     │  │  Unauthorized│
    │  Request     │  │  Data        │  │  Forbidden   │
    └──────────────┘  └──────────────┘  └──────────────┘

┌───────────────────────────────────────────────────────────────┐
│  Step 10: TOKEN RENEWAL (automatic, happens in background)    │
│                                                                │
│  When access token expires (after 1 hour):                    │
│  1. MSAL.js detects expired token                             │
│  2. Uses refresh token to get new access token                │
│  3. Stores new access token in sessionStorage                 │
│  4. User continues working (no interruption)                  │
└───────────────────────────────────────────────────────────────┘

Step-by-Step Authentication Process


Step 1: User Visits Protected Page

What happens:

Who's involved:

Result:


Step 2: Redirect to Login

What happens:

Who's involved:

Redirect URL:

https://6073ce8b-73f3-4df4-9b80-5e40cdc6965f.ciamlogin.com/.../authorize
  ?client_id=84c38b43-12e4-4c26-8292-8910d79aa532
  &redirect_uri=https://partners.egzynergy.com/authentication/login-callback
  &response_type=code

Result:



Step 3: User Enters Credentials

What happens:

Who's involved:

Result:


Step 4: Authorization Code Issued

What happens:

Who's involved:

Redirect back:

https://partners.egzynergy.com/authentication/login-callback
  ?code=0.AXAA-very-long-code-here
  &state=random-state-value

Result:


Step 5: Exchange Code for Tokens

What happens:

Who's involved:

Request to Microsoft:

POST https://.../oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
code=0.AXAA-very-long-code-here
client_id=84c38b43-12e4-4c26-8292-8910d79aa532
redirect_uri=https://partners.egzynergy.com/authentication/login-callback
code_verifier=PKCE-verifier

Response from Microsoft:

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "refresh_token": "0.AXAA...",
  "id_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "expires_in": 3600
}

Result:


Step 6: Store Tokens

What happens:

Who's involved:

What's stored:

Result:


Step 7: Redirect to Original Page

What happens:

Who's involved:

Result:


Step 8: Making API Calls

What happens (every time app calls API):

  1. User interacts with the app (e.g., viewing the overview page)
  2. Blazor app makes HTTP request to ApiService
  3. ApiAuthenticationHandler intercepts the request
  4. Handler asks MSAL.js for access token
  5. MSAL.js returns token from sessionStorage
  6. Handler adds token to request header: Authorization: Bearer eyJ0eXAi...
  7. Request sent to ApiService

Who's involved:

Result:


Step 9: API Validates Token

What happens (on ApiService):

  1. ApiService receives request with Bearer token
  2. JWT middleware extracts token from header
  3. Checks token signature (validates it's from Microsoft)
  4. Checks token issuer (must be CIAM tenant)
  5. Checks token audience (must be for this API)
  6. Checks token expiration (must not be expired)
  7. Checks user's groups claim (for authorization)
  8. If all valid → Allow request
  9. If any invalid → Return 401 Unauthorized

Who's involved:

What's validated:

Result:


Step 10: Token Renewal (Automatic)

What happens (when access token expires):

  1. Access token expires after 1 hour
  2. Next API call triggers token renewal
  3. MSAL.js uses refresh token to get new access token
  4. New access token stored in sessionStorage
  5. API call proceeds with new token
  6. User doesn't notice anything (seamless)

Who's involved:

When user must log in again: