-
Notifications
You must be signed in to change notification settings - Fork 68
Howto Authentik OIDC
This guide configures Authentik as an OIDC provider for Bindery. Users sign in via the Authentik login page and are mapped to Bindery accounts by their stable Authentik subject ID (sub).
Prerequisites:
- Authentik 2024.x+ running and reachable from Bindery
- Bindery v0.24.0+
- Authentik admin (akadmin or equivalent) access
- A public URL where Bindery is reachable (e.g. behind a reverse proxy)
Bindery must know its own public URL to construct the OAuth callback. Set it before doing anything in Authentik — the value is what you'll register as the redirect URI in step 3.
# Helm values / docker-compose / k8s deployment
environment:
BINDERY_OIDC_REDIRECT_BASE_URL: "https://bindery.example.com"Restart Bindery so the env var takes effect.
Behind a reverse proxy: This must be the public URL your proxy exposes (scheme + host + any path prefix). If unset, Bindery falls back to the request
Hostheader — which behind a proxy is the internal hostname, and will not match the redirect URI you register with Authentik.
- In the Authentik admin UI, go to Applications → Providers → Create.
- Choose OAuth2/OpenID Provider and click Next.
- Fill in:
-
Name:
Bindery -
Authorization flow:
default-provider-authorization-implicit-consent(skip the consent screen for an internal app) or...explicit-consent(show the consent screen the first time) -
Invalidation flow:
default-provider-invalidation-flow
-
Name:
- Under Protocol settings:
- Client type: Confidential
- Client ID: leave the auto-generated value (you'll copy it in step 5)
- Client Secret: leave the auto-generated value
-
Redirect URIs/Origins: add a single entry with Strict matching:
The provider id
https://bindery.example.com/api/v1/auth/oidc/authentik/callbackauthentikhere is what you'll use in Bindery's config in step 6 — pick whatever short id you like, but it must match exactly on both sides. -
Signing Key:
authentik Self-signed Certificate(the default is fine) -
Subject mode:
Based on the User's hashed ID(stable across username changes) -
Issuer mode:
Each provider has a different issuer, based on the application slug
- Under Advanced protocol settings → Scopes, select:
-
email(authentik default OAuth Mapping: OpenID 'email') -
profile(authentik default OAuth Mapping: OpenID 'profile') -
openid(authentik default OAuth Mapping: OpenID 'openid') - Optionally a
groups-emitting mapping if you want to use Bindery'sallowed_groupsfilter (see step 4 below).
-
- Finish.
- Applications → Applications → Create.
- Fill in:
-
Name:
Bindery -
Slug:
bindery(this becomes part of the issuer URL —https://auth.example.com/application/o/bindery/) -
Provider: the
Binderyprovider you just made -
Launch URL:
https://bindery.example.com/
-
Name:
- Create.
Verify the issuer URL works before going further:
curl -s https://auth.example.com/application/o/bindery/.well-known/openid-configuration | jq .issuer
# expected: "https://auth.example.com/application/o/bindery/"If this 404s, the application slug doesn't match what you typed, or the provider isn't bound to the application.
By default, Authentik's OpenID scopes do not include group membership. If you want to use allowed_groups in Bindery to restrict login to specific Authentik groups:
- Customisation → Property Mappings → Create → Scope Mapping.
- Fill in:
-
Name:
bindery-groups -
Scope name:
groups - Description: Group membership for Bindery
-
Expression:
return {"groups": [g.name for g in user.ak_groups.all()]}
-
Name:
- Finish.
- Go back to your Bindery provider (Applications → Providers → Bindery → Edit) and add
bindery-groupsto the Scopes list.
The token's groups claim will now be a list of group names. Match these in Bindery's allowed_groups field.
- Applications → Providers → Bindery → Overview.
- Copy:
- Client ID — long alphanumeric string
- Client Secret — much longer alphanumeric string (click the eye icon to reveal)
Settings → Security → OIDC Providers → Add provider, or via the API:
curl -X POST https://bindery.example.com/api/v1/settings/auth/oidc/providers \
-H "X-Api-Key: <admin-key>" \
-H "Content-Type: application/json" \
-d '{
"id": "authentik",
"name": "Authentik",
"issuer": "https://auth.example.com/application/o/bindery/",
"client_id": "<client-id-from-step-5>",
"client_secret": "<client-secret-from-step-5>",
"scopes": "openid email profile",
"allowed_groups": ""
}'Important — issuer URL gotcha: Authentik uses per-application issuers, not a single Authentik-wide issuer. The
issuervalue must behttps://auth.example.com/application/o/<app-slug>/— including the trailing slash and the app slug from step 3. The shorterhttps://auth.example.com/will appear to work (discovery succeeds) but token validation will fail withissuer mismatchbecause theissclaim in the ID token is the per-app URL.
Provider id gotcha: The
idfield (authentikin the example) must match the segment in your redirect URI from step 2. If you registered.../api/v1/auth/oidc/authentik/callbackin Authentik but useid: "ak"in Bindery, the callback URL Bindery sends to Authentik will be.../api/v1/auth/oidc/ak/callbackand you'll getredirect_uri_mismatch.
Expected result: Sign in with Authentik button appears on the Bindery login page.
- Open a private/incognito window →
https://bindery.example.com/login→ click Sign in with Authentik. - Browser redirects to Authentik → log in (or auto-login if you already have an Authentik session).
- Authentik redirects back to Bindery → Bindery validates the ID token, maps the user by
(https://auth.example.com/application/o/bindery/, <hashed-user-id>), and provisions a new local account. - Confirm the new user in Bindery Settings → Users.
If you used the Based on the User's hashed ID subject mode in step 2, renaming the user in Authentik will not orphan their Bindery account — the hashed ID is stable.
| Symptom | Cause | Fix |
|---|---|---|
Redirect URI Error / redirect_uri_mismatch from Authentik on callback |
The redirect URI Bindery sent doesn't match what's registered in the provider | First, verify Bindery actually has the env var set on the running pod — not just in your values file. On Kubernetes: kubectl get deployment bindery -o jsonpath='{range .spec.template.spec.containers[0].env[*]}{.name}={.value}{"\n"}{end}' | grep OIDC. If empty, the values file you edited isn't the one ArgoCD/Helm is actually rendering. Once set, compare carefully: BINDERY_OIDC_REDIRECT_BASE_URL + /api/v1/auth/oidc/<id>/callback must equal the strict redirect URI in the Authentik provider. The <id> segment is the Bindery provider id from step 6, not the Authentik app slug. |
issuer mismatch after a successful Authentik login |
issuer in Bindery config doesn't match the iss claim Authentik emits |
Use the per-app issuer: https://auth.example.com/application/o/<app-slug>/. The trailing slash matters. Run BINDERY_LOG_LEVEL=debug to see the actual iss value Bindery received. |
| Login button doesn't appear at all | Provider config not saved, or Bindery couldn't reach the issuer at startup | Check Bindery logs for oidc: failed to initialise provider, skipping — if present, Bindery hit an error doing OIDC discovery. Test from inside the container: curl <issuer>/.well-known/openid-configuration. |
unknown oidc provider "authentik" after a restart |
Provider is in the DB but never made it into Bindery's in-memory manager — discovery failed during startup and was silently dropped. Most often a transient race when Bindery comes up before/at the same time as the IdP, or before the pod's network stack is ready. Tracked at #461. | Logs show: oidc: failed to initialise provider, skipping id=<id> error=oidc discovery for "...": ... context canceled. Recovery: kubectl rollout restart deployment/bindery once the IdP is reachable. To reduce recurrence, ensure Bindery's pod starts after the IdP is healthy. See Howto: Recover broken OIDC. |
invalid_client from Authentik on callback |
Client secret in Bindery doesn't match what Authentik has, or the provider was set to Public client type | Re-copy the secret from Providers → Bindery in Authentik. Confirm Client type is Confidential. |
allowed_groups blocks all users |
Groups not in the ID token | Authentik's default scopes don't include groups. Add the property mapping from step 4 and add it to the provider's Scopes list. Verify with BINDERY_LOG_LEVEL=debug that the groups claim is present in the decoded token. |
| Browser loops between Bindery login and Authentik |
BINDERY_OIDC_REDIRECT_BASE_URL not set behind a proxy |
Set the env var to the public URL your proxy exposes. Restart Bindery. |
| First login works, but later restarts of Bindery break it | Authentik is unreachable during Bindery startup; provider is silently skipped on Reload()
|
Make Authentik a startup dependency (initContainer waiting on the discovery URL), or just restart Bindery after Authentik is up. |
See also: Troubleshooting — OIDC | Howto: Recover broken OIDC | docs/auth-oidc.md
Getting started
Setup guides
How-to guides — proxy auth (v1.0)
How-to guides — OIDC (v1.0)
- Google Sign-In
- GitHub OAuth via Dex
- Authelia as OIDC provider
- Authentik
- Keycloak
- Rotate OIDC client secrets
- Recover from broken OIDC
How-to guides — multi-user (v1.0)
Reference
Contributing