Authentication Modes
TheFLUX_AUTH_MODE environment variable selects the active mode. The default in development is mock.
How Entra Mode Works
WhenFLUX_AUTH_MODE=entra is active, Flux resolves every request’s identity through the following steps:
1
Easy Auth validates the token
App Service Authentication intercepts the request, validates the Microsoft Entra bearer token, and injects the authenticated principal’s claims into the
X-MS-CLIENT-PRINCIPAL request header as a Base64-encoded JSON payload.2
Flux decodes the header
AuthService Base64-decodes and JSON-parses the X-MS-CLIENT-PRINCIPAL value. If the header is absent (for example, a direct request that bypassed Easy Auth on a misconfigured route), the session is treated as unauthenticated.3
Claims are normalised
Individual claim types (
typ) and values (val) from the payload’s claims array are lowercased and collected into a dictionary. Role and group claims — including both short-form (roles, groups) and full WS-Federation URN claim types — are unioned into the set of effective assignments.4
Tenant boundary is enforced
If
FLUX_ENTRA_TENANT_ID is set, Flux compares the tid claim value against it. A mismatch returns 403 Forbidden with the message “The signed-in user belongs to a different Microsoft Entra tenant.”5
Roles are mapped
The set of effective assignments is intersected against
FLUX_ENTRA_ADMIN_ASSIGNMENTS and FLUX_ENTRA_READER_ASSIGNMENTS. An admin match grants ["admin", "reader"]; a reader-only match grants ["reader"]; no match leaves the roles list empty (authenticated but no permissions).6
Session is returned
A structured session object is returned from
GET /api/session. It includes the resolved user identity, role list, permission flags, and data-currency metadata.Authorization Roles
Flux has two application roles. Admins implicitly hold all reader permissions.Route-Level Authorization
Flux enforces authorization using two FastAPI dependency functions injected at the route level:require_reader — applied to all GET endpoints except /api/health and /api/session. Raises 401 Unauthorized if the session is not authenticated, or 403 Forbidden if the session lacks reader or admin role.
require_admin — applied to all PUT, POST, and DELETE endpoints that modify integration configuration, planning boards, budgets, virtual tags, and similar admin-only resources. Calls require_reader first, then additionally raises 403 Forbidden if the session lacks admin role with the message “Flux.Admin access is required to manage Azure integrations.”
Both dependencies return the full session dictionary so that route handlers can extract the acting user’s identity for audit attribution.
GET /api/session Response
CallGET /api/session to inspect the resolved identity, permissions, and data currency for the current request. The shell calls this on load to gate navigation items and display the signed-in user.
claimsSource is "mock", tenantId is "local", and user.id is "local-admin". When the user is not authenticated, authenticated is false and user is null.
When FLUX_ANALYTICS_SNAPSHOT_MODE=snapshot is active, dataCurrency additionally includes snapshotVersion (the version adopted by this instance), and — when a publication record exists — latestVersion and generatedAt. In the default direct mode, only mode is present.
Group ID Mappings
FLUX_ENTRA_ADMIN_ASSIGNMENTS and FLUX_ENTRA_READER_ASSIGNMENTS each accept a comma-separated list of values. Each value can be either:
- An app-role value such as
Flux.AdminorFlux.Reader— matched against therolesclaim injected by Entra app-role assignments. - An Entra group object ID (GUID) — matched against the
groupsclaim injected by a group-claims configuration. Use this when direct app-role assignment is not available.
Environment Variables
The following environment variables control authentication. Copy them from.env.example into your deployment settings.
Local Development
WithFLUX_AUTH_MODE=mock (the default), every API request is automatically resolved as a mock administrator. No Entra app registration, tenant configuration, or token is required.
"Local Admin"). Both canRead and canManageIntegrations are true, so all endpoints are accessible.
When running the Vite development server (
npm run dev), all /api requests are proxied to http://127.0.0.1:8765. The mock session is resolved by the FastAPI backend on every proxied request — the frontend does not handle authentication directly.