Gramps Web at family.niklas-stephan.de with Authentik OIDC
Last updated 05/11/2026 · gramps, authentik, oidc, docker
Setup (verified 2026-10-25)
- Compose
/data/docker/family.niklas-stephan.de/:grampsweb(ghcr.io/gramps-project/grampsweb:latest, port 5000 via Traefik, certresolverletsencrypt-tls),grampsweb_celery(same image merged via YAML anchor,labels: []so Traefik does not route it),grampsweb_redis(valkey:8-alpine). - OIDC env vars on the app service (prefix
GRAMPSWEB_):GRAMPSWEB_BASE_URL=https://family.niklas-stephan.deGRAMPSWEB_OIDC_ENABLED=trueGRAMPSWEB_OIDC_ISSUER=https://auth.handtrixxx.com/application/o/grampsGRAMPSWEB_OIDC_CLIENT_ID=gramps-webGRAMPSWEB_OIDC_AUTO_REDIRECT=true- client secret in the project
.env(mode 600, keyGRAMPSWEB_OIDC_CLIENT_SECRET)
- Authentik: application slug
gramps, OAuth2Provider “Gramps Web”, client_idgramps-web, flows = the ones used by LiteLLM/pi-agent (“Authorize Application” / “Logged out of application”). Allowed redirect URIs must include bothhttps://family.niklas-stephan.de/andhttps://family.niklas-stephan.de/api/oidc/callback/custom- gramps-web redirects to the callback path, not the root. - Created provider via Django ORM (
docker exec authentik-server python manage.py shell); redirect URIs needRedirectURIdataclass objects (from authentik.providers.oauth2.models import RedirectURI, RedirectURIType, RedirectURIMatchingMode), plain strings raiseasdict()TypeError. - grant_types gotcha (hit 2026-10-25): a provider created via ORM has
grant_types = [](the UI pre-populates it), so authorize returnserror=invalid_request(“The request is otherwise malformed”) back to the redirect_uri and gramps shows “OIDC authentication failed”. Setp.grant_types = ['authorization_code', 'refresh_token']explicitly when creating via ORM. - JWKS/signing_key gotcha (hit 2026-10-25): without a
signing_keyon the OAuth2Provider, Authentik’s/application/o/gramps/jwks/returns{}and signs ID tokens HS256 with the client secret; gramps-web’s authlib always verifies the ID token against the JWKS (KeyError: 'keys') -> “OIDC authentication failed for custom”. Fix: create aCertificateKeyPair(authentik.crypto.models; fieldsname,certificate_data,key_data) with a self-signed RSA cert and setprovider.signing_key- then JWKS serves the RS256 key. Key pair stored in authentik DB asgramps-web-oidc-signing(created 2026-10-25, valid 10 years). Note: authentik ships cryptography 50, whereCertificateBuilderis keyword-based (subject_name=, no.version()). - Scope mappings gotcha (hit 2026-10-25): ORM-created providers have no
ScopeMappinglinks, so issued access tokens carry an empty scope; the userinfo endpoint then answers 403 (log:Scope mismatch. required: {'openid'}, token_has: set()) and gramps shows “OIDC authentication failed”. Fix:p.property_mappings.add(s)for the managed defaults namedauthentik default OAuth Mapping: OpenID 'openid'/'email'/'profile'(they live inScopeMappingvia theProviderPropertyMappingthrough-model). UI-created providers get these automatically. - Roles (hit 2026-10-25): without
OIDC_GROUP_*configured, every new OIDC account is created disabled (role -1) and shows “An administrator will review your account request” - even for the site owner. Fix: Authentik groups +GRAMPSWEB_OIDC_ROLE_CLAIM=groupsandGRAMPSWEB_OIDC_GROUP_ADMIN=gramps-admin/..._EDITOR=gramps-editor/..._MEMBER=gramps-member(groups created in Authentik 2026-10-25;handtrixxxis ingramps-admin). The managed OpenID ‘profile’ scope mapping already emits agroupsclaim. Roles: OWNER=4, ADMIN=5, EDITOR=3, CONTRIBUTOR=2, MEMBER=1, GUEST=0, DISABLED=-1 (ADMIN is above OWNER). Fail-closed: a user in no mapped group becomes disabled. Role is re-evaluated on every login. - Two accounts exist: local
handtrixxx(role 5, created with a password before OIDC) and the OIDC-createdhandtrixxx_1. Merge with the UI flow Settings -> “link SSO” (API:POST /api/oidc/link/then/oidc/login/?provider=custom&link=<ticket>), or keep both and delete the spare via the admin user page. - Debug tip: gramps logs the actual authlib traceback (
docker logs <grampsweb>); authentik logsScope mismatchwarnings. The flow API in 2026.x isPOST /api/v3/flows/executor/<slug>/(old/api/-/flow/is gone).
Gotchas
- Health endpoint is
/health(not/api/health). celery -A ... pingdoes not exist in the shipped celery version; celery healthcheck usesgrep -q celery /proc/1/cmdline && </dev/tcp/grampsweb_redis/6379.- Login flow:
GET /api/oidc/login/?provider=custom&tree=Familie-> 302 to Authentik. Withoutproviderparam it returns 422. - No local users yet (users table empty); first OIDC login creates the account. Role mapping configured 2026-10-25 via Authentik groups (see below).
Source: Wiki.js