Set up OIDC SSO#
Goal: connect swarm to your identity provider (Google Workspace, Okta, Azure AD, Auth0). Time: ~15 minutes.
Why#
- Identity hygiene — users sign in with their corporate account, no separate swarm passwords to manage
- Audit — every action is attributable to a real user identity
- Policy — role-based access control ties back to IdP groups
- Compliance — HIPAA / SOC 2 / RBI FREE-AI all want this
1. Register swarm with your IdP#
Create an OpenID Connect application in your IdP:
- Redirect URI:
https://<your-swarm-url>/api/v1/auth/oidc/callback - Scopes:
openid email profile - Grant types:
authorization_code
The IdP gives you three values to copy: client ID, client secret, issuer URL (aka discovery endpoint).
- console.cloud.google.com → APIs & Services → Credentials → Create credentials → OAuth client ID
- Application type: Web application
- Authorized redirect URI:
https://<your-swarm>/api/v1/auth/oidc/callback - Issuer URL is always:
https://accounts.google.com
- Okta Admin → Applications → Create App Integration → OIDC - OpenID Connect → Web Application
- Sign-in redirect URI:
https://<your-swarm>/api/v1/auth/oidc/callback - Issuer URL:
https://<your-org>.okta.com
- Entra ID → App registrations → New registration
- Redirect URI:
https://<your-swarm>/api/v1/auth/oidc/callback(Web platform) - Certificates & secrets → New client secret → copy value (only shown once)
- Issuer URL:
https://login.microsoftonline.com/<tenant-id>/v2.0
- Auth0 dashboard → Applications → Create application → Regular Web Applications
- Allowed callback URLs:
https://<your-swarm>/api/v1/auth/oidc/callback - Issuer URL:
https://<your-tenant>.auth0.com/
2. Configure swarm#
Add to .env:
SWARM_OIDC_ENABLED=true
SWARM_OIDC_ISSUER=https://accounts.google.com
SWARM_OIDC_CLIENT_ID=<your-client-id>.apps.googleusercontent.com
SWARM_OIDC_CLIENT_SECRET=<your-client-secret>
SWARM_OIDC_REDIRECT_URI=https://<your-swarm>/api/v1/auth/oidc/callback
SWARM_OIDC_SCOPES=openid email profile
SWARM_OIDC_AUTO_PROVISION=true # creates swarm users on first login
SWARM_OIDC_DEFAULT_ROLE=viewer # new users land here
Restart the api container.
curl -X PUT http://localhost:8000/api/v1/auth/oidc/config \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"issuer": "https://accounts.google.com",
"client_id": "...",
"client_secret": "...",
"redirect_uri": "https://<your-swarm>/api/v1/auth/oidc/callback",
"scopes": ["openid", "email", "profile"],
"auto_provision": true,
"default_role": "viewer"
}'
3. Test the flow#
- Open an incognito browser →
https://<your-swarm>/ - Click Sign in with SSO
- Redirected to your IdP → authenticate
- Redirected back to swarm dashboard → logged in
Verify with:
4. Map IdP groups to swarm roles#
swarm has 3 built-in roles: viewer, operator, admin. Map IdP groups via policy:
# config/permission_policies_org.yaml
rules:
- if:
claim: groups
contains: "swarm-admins"
then_role: admin
- if:
claim: groups
contains: "swarm-operators"
then_role: operator
- else:
role: viewer
Restart to apply. Now users land with the right role based on their IdP group membership at login.
5. Enforce OIDC-only (disable local passwords)#
Once SSO is working:
Local login via the seeded admin no longer works. All sign-ins must go through OIDC. Reversible in case of IdP outage (you'll need to exec into the API container and flip the flag via env var).
6. Per-IdP group claim#
Some IdPs emit groups differently:
| IdP | Claim key | Notes |
|---|---|---|
| Google Workspace | groups |
Requires admin to enable Directory API + grant groups.readonly scope |
| Okta | groups |
Default; ensure app config includes groups in ID token |
| Azure AD | groups |
Emits object IDs, not names by default — either configure "group display names" or use the object ID in the policy |
| Auth0 | https://yourtenant/groups |
Use a Rule to add groups to the ID token |
Debug: swarm auth oidc debug decodes the current user's ID token so you can see the claims.
Advanced#
Refresh tokens#
swarm caches the access token + refresh token. When the access token expires, a background refresh kicks in. If refresh fails (user deprovisioned at IdP), the next API call returns 401.
MFA#
swarm doesn't enforce MFA itself — it's inherited from your IdP. Configure MFA at the IdP and it applies automatically.
SAML#
SAML is not yet supported. If you need it, open an issue. We plan to add it after SCIM in a later release.
SCIM (user provisioning)#
Automated provisioning / deprovisioning via SCIM 2.0 is on the roadmap for v0.12. For now, auto-provision on first login + role-via-groups covers most teams.
Troubleshooting#
Redirect URI mismatch error
The URI registered at your IdP must match SWARM_OIDC_REDIRECT_URI exactly — including trailing slash, scheme (http vs https), and port.
401 after OIDC redirect
Check api logs for the OIDC callback — usually indicates clock skew (>30s between swarm and IdP) or a missing scope.
Groups claim missing from ID token
Depends on IdP config. For Google, Directory API + groups.readonly scope needed. For Azure AD, enable "groups claim" in app manifest.
Next#
- Permissions & audit — how roles translate to rules
- Reference: configuration — every
SWARM_*env var