Skip to content

Authentication Flow

The dashboard uses the Microsoft Entra ID authorization-code flow (MSAL) for browser-based users. Administrative and internal API calls use a shared HMAC secret or managed-identity credentials.


Browser auth (OIDC authorization-code flow)

sequenceDiagram
    autonumber
    participant B as Browser
    participant API as App Service
    participant Entra as Microsoft Entra ID

    B->>API: GET /some-protected-page
    API->>API: No session cookie → start auth
    API->>B: 302 → /auth/signin?redirect=/some-protected-page

    B->>API: GET /auth/signin
    API->>B: 302 → Entra authorize endpoint\n(client_id, redirect_uri, scope=openid profile email)

    B->>Entra: GET /authorize (user follows redirect)
    Entra->>B: Render login page (MFA if required)

    B->>Entra: Submit credentials
    Entra->>B: 302 → /auth/callback?code=XXXX&state=YYY

    B->>API: GET /auth/callback?code=XXXX
    API->>Entra: POST /token (code + client_secret)
    Entra-->>API: { access_token, id_token, refresh_token }

    API->>API: Validate id_token\nExtract oid, groups, roles\nCreate express-session

    API->>B: 302 → /some-protected-page\n(Set-Cookie: connect.sid)

    B->>API: GET /some-protected-page\n(Cookie: connect.sid)
    API->>API: Session lookup → authorised
    API-->>B: 200 — page content

Authorisation levels

Once authenticated, routes are gated by three roles derived from Entra group membership:

Level Middleware Who
Public none Anyone, including unauthenticated callers
User requireAuth Any authenticated Entra user in the tenant
Admin requireAdmin Members of the configured admin Entra group
Internal INGEST_API_KEY HMAC Worker-to-API calls with shared secret header

Routes are documented in API Reference → Auth levels.


Session storage

Sessions are stored in Azure SQL (AppSessions table) using connect-mssql-v2.

  • Session lifetime: 8 hours (configurable via SESSION_MAX_AGE_MS)
  • Secret: stored in Key Vault as capdash-session-secret; injected as Key Vault reference in App Settings
  • Cookie: httpOnly, secure, sameSite: lax

Token handling

Token Usage Stored where
id_token User identity, group claims Discarded after session creation
access_token ARM calls on behalf of user (not used — MI preferred) Not stored
refresh_token Kept for silent renewal Encrypted in session row

Warning

Access tokens are never written to localStorage or sessionStorage. Session state lives server-side in SQL.