Federated identity layer
AlphaSwarm wraps every identity / token operation in a pluggable
:class:alphaswarm.auth.providers.IdentityProvider. The provider drives both
user authentication (login, JWT validation, refresh) and
service-to-service auth (M2M tokens that downstream services like
Polaris / Trino consume via the credential resolver).
The pieces port (with attribution) from
alphaswarm_snippets/inspiration/auth0-server-python-main (MIT, Copyright Auth0, Inc.)
into AlphaSwarm-native modules.
Architecture
Components
| Component | Path |
|---|---|
| Provider ABC + metaclass | alphaswarm/auth/providers/protocol.py |
| Auth0 / generic OIDC / mock concrete providers | alphaswarm/auth/providers/ |
| OIDC HTTP plumbing (discovery, JWKS, token endpoint) | alphaswarm/auth/oidc_client.py |
| PKCE helpers (RFC 7636 S256) | alphaswarm/auth/pkce.py |
| Cookie / Redis session stores | alphaswarm/auth/session/ |
| JWE cookie crypto (HKDF-SHA256 + A256CBC-HS512) | alphaswarm/auth/session/crypto.py |
| M2M token issuer | alphaswarm/auth/m2m.py |
| Login / callback / logout routes | alphaswarm/api/routes/auth.py |
| Backend JWT validator | alphaswarm/auth/oidc.py |
Login flow (backend session)
- Browser hits
GET /auth/login(optionally with areturn_to). - AlphaSwarm generates a PKCE verifier + state, stashes them in an encrypted transaction cookie (10-minute TTL), redirects to the provider's authorize URL.
- Provider posts the authorization code to
GET /auth/callback. - AlphaSwarm looks up the transaction cookie by
state, callsprovider.exchange_code(...), and stores the resulting token set in an encrypted session cookie (or Redis). - Subsequent requests carry the cookie; AlphaSwarm decrypts it on demand
and exposes the user via the existing
current_userdep.
The bearer-token flow (Authorization: Bearer) keeps working unchanged
— the SPA can pick either path via the backend_session_supported
flag in /auth/config.
M2M flow
When ALPHASWARM_AUTH_M2M_ENABLED=true:
- AlphaSwarm startup calls
alphaswarm.auth.m2m.install_m2m_store(), which adds :class:M2MStore(priority 10) to the credential resolver chain. - A service like
polaris_clientresolvesCredentialKey("polaris", "oauth")through :func:alphaswarm.credentials.get_resolver. - The M2M store fetches
provider.m2m_token(audience, scope)(Auth0client_credentialsgrant) and returns aCredentialwithaccess_token/tokenset. - The resolver merges this hit with the env-store payload (which
carries the static
client_id), so consumers see one mergedCredential. - Tokens cache in
M2MTokenIssueruntil expiry minus a 30-second skew, so we don't mint per request.
The resolver chain falls through to the file/env stores if the M2M issuer fails or is disabled — you never get a worse outcome than the pre-M2M state.
Configuration
The full env knob set lives in .env.example under the "Federated
identity (M2 / M3)" section. The minimum for an Auth0 deployment:
ALPHASWARM_AUTH_PROVIDER=auth0
ALPHASWARM_AUTH_OIDC_ISSUER=https://your-tenant.auth0.com
ALPHASWARM_AUTH_OIDC_AUDIENCE=https://alphaswarm.local/api
ALPHASWARM_AUTH_OIDC_CLIENT_ID=...
ALPHASWARM_AUTH_OIDC_CLIENT_SECRET=...
ALPHASWARM_AUTH_LOGIN_CALLBACK=http://localhost:8000/auth/callback
ALPHASWARM_AUTH_LOGOUT_CALLBACK=http://localhost:3000/
ALPHASWARM_AUTH_SESSION_SECRET=$(openssl rand -hex 32)
ALPHASWARM_AUTH_M2M_ENABLED=true
ALPHASWARM_AUTH_M2M_AUDIENCE=https://alphaswarm.local/services
Adding a new provider
- Subclass :class:
alphaswarm.auth.providers.IdentityProviderand setprovider_kind(the dispatch key matched againstALPHASWARM_AUTH_PROVIDER). - Either inherit from
:class:
alphaswarm.auth.providers.GenericOidcProvider(and override only the bits that diverge) or roll your own. - The metaclass auto-registers; restart the API and set
ALPHASWARM_AUTH_PROVIDER=<your_kind>.
Testing
tests/auth/ contains the canonical test patterns:
test_pkce.py— RFC 7636 conformance.test_session_crypto.py— JWE round-trips, wrong-key rejection.test_oidc_client.py— token endpoint mock-driven tests.test_providers.py— Auth0 / generic OIDC / mock dispatch.test_m2m.py— issuer caching, resolver integration.
All tests run hermetic; nothing hits the network.
Account management surface (Phase 7)
Phase 7 adds a dedicated account-management API surface under /me/*
implemented in alphaswarm/api/routes/me.py.
These routes expose profile updates, MFA and session operations, linked
identity management, and self-service account actions while keeping the
Auth0 Management API boundary centralized.
The Auth0 Management API integration lives in
alphaswarm/auth/management_api.py. Scope
enforcement for protected endpoints is available through
alphaswarm/auth/auth0_fastapi.py via
Auth0FastAPI opt-in dependencies. Audit and invite persistence for
this surface is recorded in
alphaswarm/persistence/models_audit.py
(security_audit_events and tenancy_invites), and events are emitted
through alphaswarm/auth/audit.py.
Microsoft Entra ID secondary IdP (Phase 7)
AlphaSwarm's primary Microsoft pattern is federation through Auth0 Universal
Login using an Auth0 Microsoft Enterprise Connection, documented in
alphaswarm_docs/auth0-microsoft-federation.md.
This keeps Auth0 as the default IdP while preserving one hosted login
surface and one claims projection path.
Direct Entra authentication remains supported as a fallback through
alphaswarm/auth/providers/msal_entra.py.
When ALPHASWARM_AUTH_PROVIDER=msal_entra, the legacy MsalEntraProvider
path activates without changing the backend tenancy-link semantics.