SAML with authentik
Tested against authentik 2026.5. Goal: login through authentik works and your admin user gets org_admin instead of "forbidden".
All steps happen in the Admin Interface (https://<authentik-host>/if/admin/). Menu map for the settings people struggle to find:
| What | Where |
|---|---|
| Create a group | Directory → Groups |
| Property mappings (groups/email) | Customization → Property Mappings |
| Edit provider (ACS, certs, mappings) | Applications → Providers |
| Create/upload certificates | System → Certificates |
The two "missing" fields
The property-mapping selector and the Verification Certificate field live on the provider under the collapsed "Advanced protocol settings" section — expand it first.
1. Create the admin group
Directory → Groups → Create
- Name:
orbital-admins(any name — but exactly this string goes into the OrbitalReg values later). - Open the group → Users tab → Add existing user → add your login user.
2. Property mappings
With saml.idpPreset: "authentik" (recommended), OrbitalReg reads authentik's default SAML property mappings — including the stock groups mapping (http://schemas.xmlsoap.org/claims/Group). No custom mapping is needed; skip to step 3.
Running without the preset (entra default)?
Without the preset, OrbitalReg only reads Microsoft's groups URI, so you must create a custom mapping. Customization → Property Mappings → Create → "SAML Provider Property Mapping":
Name:
OrbitalReg GroupsSAML Attribute Name:
http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsExpression:
pythonreturn [group.name for group in request.user.ak_groups.all()]
Then select it on the provider (step 3). The preset exists precisely to make this step unnecessary.
3. Configure the provider
Applications → Providers → <your OrbitalReg provider> → Edit
Protocol settings:
- ACS URL:
https://<domain>/saml/acs— https, no trailing slash (the SP compares exactly). - Issuer / Audience:
https://<domain>/saml/metadata— must matchsaml.entityIDin the values exactly. - Service Provider Binding:
Post. The defaultRedirectdelivers the SAML response as GET, and OrbitalReg's ACS accepts only POST → HTTP 405 after login. - Signing Certificate: pick a keypair (e.g. "authentik Self-signed Certificate"). It signs the assertion and lands in the metadata that OrbitalReg fetches.
Property mappings ("Available / Selected" two-column selector) — select:
authentik default SAML Mapping: Emailauthentik default SAML Mapping: Name- the default Groups mapping (or
OrbitalReg Groupsif you created the custom one)
NameID Property Mapping: authentik default SAML Mapping: Email (OrbitalReg identifies users by email).
Advanced protocol settings (expand it):
- Verification Certificate: the OrbitalReg SP certificate (step 4). Required because OrbitalReg signs its login requests; without it authentik may reject or ignore the request.
4. Register the SP certificate ("the raw cert")
authentik must know the public half of the SP keypair OrbitalReg signs with. If you don't have one yet:
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout sp.key -out sp.crt -days 3650 -subj "/CN=orbitalreg-sp"System → Certificates → Create
- Name:
orbitalreg-sp - Certificate: paste the contents of
sp.crt - Private Key: leave empty (authentik only verifies)
Back in step 3, select it as the Verification Certificate. On the OrbitalReg side, sp.crt + sp.key go into the Helm secret (saml.existingSecret or saml.certPEM/keyPEM).
5. Copy the metadata URL
Applications → Providers → <provider> → "Metadata download" URL:
https://<authentik-host>/application/saml/<application-slug>/metadata/Use the public authentik host — authentik builds the endpoint URLs in the metadata from the host the metadata was fetched on. This URL becomes saml.idpMetadataURL.
6. Values + deploy
A complete example ships as charts/orbitalreg/values-authentik.yaml.example. The essentials:
saml:
enabled: true
idpPreset: "authentik"
rootURL: "https://registry.example.com"
entityID: "https://registry.example.com/saml/metadata"
idpMetadataURL: "https://<authentik-host>/application/saml/<app-slug>/metadata/"
existingSecret: "orbitalreg-saml-sp" # TLS secret with sp.crt / sp.key
auth:
adminGroups:
- "orbital-admins" # exact group name from step 1helm upgrade orbitalreg charts/orbitalreg -n <ns> -f values-authentik.yaml7. Verify
- Log out completely (including the authentik session), log back in.
- Open
https://<domain>/auth/whoami:groupsmust containorbital-admins,rolesmust containorg_admin.
If groups stays empty, add your login email to auth.adminGroups as an immediate fallback (it always matches, because the email is always in the assertion), redeploy, re-login — then debug the group mapping calmly.
8. Optional: IdP-initiated login
By default OrbitalReg only accepts a SAML response that answers an AuthnRequest it issued (SP-initiated: user clicks "Log in" on OrbitalReg first). Clicking the authentik application tile directly skips that step — authentik posts an unsolicited assertion — which OrbitalReg rejects unless you opt in.
saml:
allowIdpInitiated: true
idpInitiatedRelayStates: ["/"] # optional; "/" is the default anywayCSRF / login-forgery trade-off
Accepting an unsolicited assertion is the well-known SAML IdP-initiated weakness: there is no SP-issued request ID to match the response against, so anyone who can get a captured assertion POSTed to /saml/acs (e.g. a malicious page that replays one) can log a victim into an attacker-chosen session. Only turn this on if you trust authentik to gate the application tile behind its own auth, and keep idpInitiatedRelayStates limited to the paths you actually want IdP-initiated logins to land on — anything outside that whitelist is rewritten to / rather than followed, which closes the matching open-redirect angle (an IdP-supplied RelayState would otherwise become the raw post-login redirect target).
After the flag is set, clicking the authentik app tile should land you logged in on the OrbitalReg dashboard.
Troubleshooting
Real cases from the first rollout:
| Symptom | Cause | Fix |
|---|---|---|
Pod crashes, saml init failed in log | SP can't load idpMetadataURL (TLS, DNS, wrong slug) | curl the URL from the pod network; use authentik's "Copy download URL" |
| "response code null" on login click | Metadata contains internal SSO URLs (fetched via internal address) | Set idpMetadataURL to the public authentik URL |
Login works, but roles: reader despite correct group in whoami | Group list joined with commas; env slices split only on whitespace → one giant non-matching string | Fixed in current charts (space-joined). Check kubectl exec … env | grep ADMIN_GROUPS |
| 405 after the authentik login | Provider field "Service Provider Binding" is Redirect (default) — response arrives as GET, ACS is POST-only | Set Service Provider Binding = Post |
404 on /saml/acs | ACS URL with trailing slash or different path — exact comparison | ACS URL exactly https://<domain>/saml/acs |
405 when opening /saml/acs directly in the browser | Normal — GET on a POST-only endpoint | Not an error |
groups empty in whoami | Mapping not "Selected" on the provider, wrong attribute URI / missing preset, or no fresh login after a mapping change | Check preset + Selected mappings; log out completely and back in (groups are baked into the session at login) |
Reference: what OrbitalReg reads (preset authentik)
| OrbitalReg expects | SAML attribute name |
|---|---|
| Email (identity) | http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress |
| Groups (→ role) | http://schemas.xmlsoap.org/claims/Group |
| Display name | http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name |
See the SSO overview for how these map to roles and how to override individual claim names.