Authentik OIDC
Dashy supports using Authentik as its OIDC provider.
Authentik is an open source identity provider that speaks OIDC, OAuth 2.0, SAML 2.0 and LDAP. It runs in Docker, has a polished admin UI, and supports MFA, social login, and per-application group policies, which makes it a good fit for self-hosted setups where you want a single login across many services.
Contentsβ
- 1. Deploy Authentik
- 2. Configure Authentik
- 3. Enabling Authentik in Dashy
- 4. Groups and Visibility
- 5. Silent token renewal (optional)
- Troubleshooting
- Config Example
- How it Works
1. Deploy Authentikβ
If you've not already done so, spin up an Authentik instance, following the official docs. The compose file below is a minimal local setup.
A .env file alongside the compose file (generate fresh secrets with openssl rand -hex 32):
AUTHENTIK_TAG=2024.12
PG_PASS=replace-me-with-random-hex
AUTHENTIK_SECRET_KEY=replace-me-with-random-hex
AUTHENTIK_BOOTSTRAP_PASSWORD=change-me-now
AUTHENTIK_BOOTSTRAP_TOKEN=replace-me-with-random-hex
AUTHENTIK_TAG pins the Authentik version. 2024.12 is a tested baseline; any 2024.10+ release works too (the Invalidation flow field below needs 2024.10 or newer).
Example docker-compose.yml
name: authentik
services:
postgresql:
image: docker.io/library/postgres:16-alpine
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
start_period: 20s
interval: 10s
retries: 5
timeout: 5s
volumes:
- ./data/postgres:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: ${PG_PASS}
POSTGRES_USER: authentik
POSTGRES_DB: authentik
redis:
image: docker.io/library/redis:7-alpine
command: --save 60 1 --loglevel warning
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
start_period: 20s
interval: 10s
retries: 5
timeout: 3s
volumes:
- ./data/redis:/data
server:
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}
restart: unless-stopped
command: server
environment: &authentik-env
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: authentik
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD}
AUTHENTIK_BOOTSTRAP_TOKEN: ${AUTHENTIK_BOOTSTRAP_TOKEN}
AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL}
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
ports:
- "9000:9000"
- "9443:9443"
depends_on:
postgresql: {condition: service_healthy}
redis: {condition: service_healthy}
worker:
image: ghcr.io/goauthentik/server:${AUTHENTIK_TAG}
restart: unless-stopped
command: worker
environment: *authentik-env
depends_on:
postgresql: {condition: service_healthy}
redis: {condition: service_healthy}
Bring it up:
docker compose up -d
First boot runs database migrations and takes a minute or two. Once the server container is healthy, open http://localhost:9000 and sign in as akadmin with the bootstrap password.
2. Configure Authentikβ
Create the groups scopeβ
Authentik doesn't expose group membership in the id_token by default. Dashy needs it for the adminGroup check and for the showForGroups / hideForGroups visibility rules.
- Go to Customization > Property Mappings
- Click Create > Scope Mapping
- Set Name to
groups - Set Scope name to
groups - Set Expression to:
return {"groups": [g.name for g in request.user.ak_groups.all()]}
- Click Finish
Create the OIDC providerβ
- Go to Applications > Providers
- Click Create, pick OAuth2/OpenID Provider, click Next
- Set Name to
Dashy - Set Authorization flow to
default-provider-authorization-implicit-consent(usedefault-provider-authorization-explicit-consentif you want users to confirm sign-in each time) - Set Invalidation flow to
default-provider-invalidation-flow(required on Authentik 2024.10 and newer) - Under Protocol settings:
- Client type:
Public - Client ID:
dashy, or leave the auto-generated value and copy it for later - Redirect URIs with matching mode
Strict, one URL per line. Register both the bare URL and the trailing-slash version:https://dashy.example.comhttps://dashy.example.com/
- Signing Key: the built-in
authentik Self-signed Certificateis fine
- Client type:
- Expand Advanced protocol settings:
- Add
openid,profile,email, and thegroupsscope you just created to Selected Scopes - Turn Include claims in id_token on
- Add
- Click Finish
Create the applicationβ
- Go to Applications > Applications
- Click Create
- Set Name to
Dashy - Set Slug to
dashy(this becomes part of the issuer URL:<host>/application/o/<slug>/) - Set Provider to the
Dashyprovider you just made - Click Create
Now open the Dashy provider again (Applications > Providers > Dashy) and copy the OpenID Configuration Issuer URL shown on the page (e.g. https://auth.example.com/application/o/dashy/). The provider only displays a valid URL once it's bound to an application. You'll need this for Dashy's endpoint setting later.
Create the admin groupβ
- Go to Directory > Groups
- Click Create
- Set Name to
dashy-admins - Click Create
- Open the new group, click Users, and add any users who should have admin rights in Dashy
Create test usersβ
If you want separate accounts beyond akadmin:
- Go to Directory > Users
- Click Create, fill in Username, Name and Email, click Create
- On the new user's page, click Set password, set a password, click Update
- Add the user to
dashy-adminsfor admin access, or leave them out for a non-admin
Restrict who can access Dashy (optional)β
By default any Authentik user can sign in to Dashy. To limit access to one or more groups, bind a group policy to the Dashy application; Authentik then denies sign-in to anyone outside those groups. This is separate from adminGroup, which only controls who gets admin rights inside Dashy, not who can access it at all.
- Go to Applications > Applications and open the
Dashyapplication
screenshot
- Open the Policy / Group / User Bindings tab and click Bind existing policy
screenshot
- Switch to the Group tab, choose the group that should have access, make sure Enabled is on, and click Create
screenshot
Access is now limited to members of the bound group. Add another binding for each additional group that should be allowed in.
3. Enabling Authentik in Dashyβ
Finally, you need to tell Dashy to use Authentik. This goes in the appConfig.auth section of your main /user-data/conf.yml.
appConfig:
...
disableConfigurationForNonAdmin: true
auth:
enableOidc: true
oidc:
clientId: dashy
endpoint: https://auth.example.com/application/o/dashy/
adminGroup: dashy-admins
scope: openid profile email groups
Where:
disableConfigurationForNonAdmin- Prevent read/write config access to non-admin usersauth.enableOidc- Set the auth mode to OIDCclientId- The Client ID from the Authentik provider (exact, case-sensitive)endpoint- The OpenID Configuration Issuer URL from the provider page. Use the bare issuer, not the discovery URL; Dashy appends/.well-known/openid-configurationitselfadminGroup- Name of the Authentik group that grants admin in Dashy (matches thedashy-adminsgroup above). To use roles instead, setadminRole, but Authentik has norolesclaim by default, so groups are the simpler path herescope- Space-separated list of scopes to request. Must includegroupswhenadminGroupis set, otherwise the id_token won't carry the claim
To let visitors view a read-only dashboard without signing in, add enableGuestAccess: true under auth; they skip the Authentik login, and admins still get edit access after signing in. See guest access for the details.
Restart Dashy for these changes to take effect.
If Authentik runs on a different host or behind a reverse proxy, make sure endpoint is reachable from inside the Dashy container, and that the issuer URL the provider advertises matches endpoint exactly.
Everything should now be fully configured and working π When you load Dashy, you'll be redirected to Authentik's login page. After signing in you will land back on Dashy's homepage with full access, and all of Dashy's client, server and asset endpoints will be locked behind authentication.
4. Groups and Visibilityβ
Once group membership is in the id_token, you can use it to hide or show pages, sections and items in Dashy, with showForGroups and hideForGroups under displayData.
To make an Admin section visible only to members of dashy-admins:
displayData:
showForGroups:
- dashy-admins
Both showForGroups and hideForGroups accept a list of group names (showForRoles / hideForRoles do the same for a roles claim). If a user matches an entry they're allowed or excluded as defined.
sections:
- name: Internal Tools
displayData:
showForGroups: ['dashy-admins']
hideForGroups: ['guests']
items:
- title: Hidden from interns
displayData:
hideForGroups: ['interns']
5. Silent token renewal (optional)β
By default, when your token expires Dashy sends you back through Authentik's login to get a new one. Set enableSilentRenew: true to have Dashy refresh the session quietly in the background instead, using a refresh token:
oidc:
clientId: dashy
endpoint: https://auth.example.com/application/o/dashy/
adminGroup: dashy-admins
scope: openid profile email groups
enableSilentRenew: true
Dashy adds the offline_access scope to its request automatically. Authentik ships an offline_access scope mapping by default, so just make sure it's listed under the provider's Advanced protocol settings > Selected Scopes. It's off by default, and if a refresh ever fails Dashy falls back to the normal sign-in. See silent token renewal for the full notes and caveats.
How often renewal fires is set by the provider's Access Token validity (and Refresh Token validity) under Advanced protocol settings in Authentik; the defaults suit most people.
Troubleshooting common Authentik Issuesβ
Two places will tell you what went wrong. Client-side problems, like a token Dashy can't use or a renewal that didn't take, are logged to the browser console tagged SSO or OIDC, so open your browser's DevTools and check the Console tab. Token verification failures show up in the Dashy server logs instead. Check whichever fits what you're seeing.
Migrations still running on first bootβ
Problem: Authentik returns 502 or never reaches the login page right after docker compose up.
Solution: First boot runs database migrations and can take a minute or two. Tail the logs with docker compose logs -f server and wait for the uvicorn startup line before opening the UI.
Redirect loop after loginβ
Problem: Browser bounces between Dashy and Authentik repeatedly.
Solution: endpoint in conf.yml probably includes .well-known/openid-configuration. Drop everything from .well-known onwards; Dashy appends it itself.
invalid_redirect_uriβ
Problem: Authentik shows "invalid redirect URI" after submitting credentials.
Solution: The URL Dashy is being served from doesn't exactly match what's registered on the provider. Register both the bare URL and the trailing-slash variant (e.g. https://dashy.example.com and https://dashy.example.com/), keep matching mode on Strict, and make sure the scheme matches (http vs https).
Logged in but config saves return 403β
Problem: User authenticates fine, but saving the dashboard returns 403.
Solution: The id_token isn't carrying the group claim. Paste the token (from localStorage, key idToken) into jwt.io and look for groups. If it's missing, the groups scope mapping isn't attached to the provider's Selected Scopes or Include claims in id_token is off. If the claim is there but the user isn't in it, add them to the dashy-admins group.
Issuer mismatch behind a reverse proxyβ
Problem: Server logs show unexpected "iss" claim value. The browser reaches Authentik over HTTPS, but Authentik advertises an HTTP issuer in its discovery document.
Solution: Set AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS on the Authentik server and worker containers to include your proxy's IP range (e.g. 172.16.0.0/12 for default Docker bridges), and make sure the proxy forwards X-Forwarded-Proto: https. Once Authentik trusts the proxy, its discovery document will advertise the public HTTPS URL.
Audience mismatch on token verificationβ
Problem: Server logs show unexpected "aud" claim value. Every auth'd API call returns 401.
Solution: clientId in conf.yml must exactly match the provider's Client ID field. If you let Authentik auto-generate one, copy the exact value (including case) from the provider page.