Federated identity layer
AlphaSwarm centralizes identity and token operations through the unified alphaswarm_auth service, or the pluggable
:class:alphaswarm.auth.providers.IdentityProvider for legacy/local deployments. The auth service acts as the central Identity and Access Management (IAM) hub, providing both
user authentication (login, JWT validation, refresh) and
centralized authorization resolution (Scope Resolution).
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 |
| Unified Auth Service | alphaswarm_auth/ |
| 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 |
Centralized Authorization (Scope Resolution)
Per the CP-side maturation, AlphaSwarm now centralizes authorization resolution in the alphaswarm_auth service. Instead of each service independently re-deriving the AlphaSwarm scope set from raw JWT claims, they call the introspection endpoint:
- Consuming Service (e.g.,
alphaswarm_controller) receives a bearer token. - Consuming Service calls
POST /auth/introspecton thealphaswarm_authservice. - Auth Service validates the token and resolves the full AlphaSwarm scope set using the canonical RBAC lattice and custom group/role mappings.
- Auth Service returns the
HydratedUserincluding the resolvedscopes. - Consuming Service enforces access based on these resolved scopes.
This ensures consistent authorization logic across the platform and simplifies the addition of new identity providers. For more details, see the alphaswarm_auth architecture documentation.
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.
Legacy demo SAML provisioning
This section documents the retired demo-only SAML provisioning gate. The current alpha-testing topology uses the active Entra/Cloudflare Access paths: MacBook client apps and local servers target the platform hosted on the local Ubuntu box. Do not enable demo provisioning for the current alpha stack.
The legacy hosted demo (demo.alpha-swarm.ai) could provision real
AlphaSwarm accounts for a curated set of design partners who signed in through
a SAML identity provider, while denying everyone else. SAML was brokered
upstream (an Auth0 Enterprise SAML connection or an Entra SAML/WS-Fed
enterprise app) and arrived at the backend as a normal OIDC JWT — there is no
native SAML SP.
Provisioning is gated by a per-email allowlist:
- The
demo_approved_emailstable (models_tenancy.py, Alembic0089) holds the approved emails (lifecycleapproved/revoked, plus a reservedpending), each with adefault_roleand optional scope. - On first login,
provision_user_from_claimscallsis_demo_gated_login(claims)and, when true,evaluate_demo_approval. Anapprovedemail mints a realUser+ membership at the row's role; an unapproved email is denied before any row is created (ProvisioningDenied→ HTTP 403 with an RFC 9470WWW-Authenticatechallenge) in strict mode, or logged-and-allowed in permissive mode. - Revoking an approval ejects an already-provisioned demo user on their
next request (strict mode) via the
_DEMO_APPROVAL_REJECT_STATUSEScheck inalphaswarm/api/security.py, mirroring theEntraTenantLinksuspend/revoke handling.
A login only counts as "demo SAML" when the brokering connection
(connection / idp claim, or a samlp|<conn>|… subject) is listed in
ALPHASWARM_AUTH_DEMO_CONNECTION_NAMES or backed by an
IdpConnectionRecord (kind generic_saml) whose config.demo is true —
so production Entra logins are never gated.
Admins manage the allowlist through
/tenancy/orgs/{org_id}/idp-connections/{connection_id}/approved-emails
(admin role + step-up MFA + audit), surfaced in the operator UI by
ApprovedEmailsEditor.
Configuration
# Legacy demo backend only (NOT the current alpha or hosted-platform deployment).
ALPHASWARM_AUTH_DEMO_PROVISIONING_ENABLED=true
ALPHASWARM_AUTH_DEMO_ENFORCE=permissive # flip to strict after burn-in
ALPHASWARM_AUTH_DEMO_CONNECTION_NAMES=demo-saml
ALPHASWARM_AUTH_DEMO_PROVISIONING_ENABLED is mutually exclusive with
ALPHASWARM_AUTH_HOSTED_PLATFORM_MODE (a boot validator refuses both) so
the gate can never run on a production Entra surface. For the current alpha
stack, leave this disabled. Full historical design + rollout runbook lives in
the monolith repo at
.cursor/plans/saml-demo-approved-email-provisioning.plan.md.