OIDC provider
GateKeeper is a full OIDC identity provider. Any application that supports OIDC can delegate authentication to it - Traefik Manager, Grafana, Jellyfin, Portainer, or any custom app.
What this means
Section titled “What this means”Instead of each app managing its own login, they redirect users to GateKeeper. GateKeeper handles authentication (password, passkey, TOTP, email OTP) and returns a verified identity token. Apps never see credentials.
Endpoints
Section titled “Endpoints”| Purpose | URL |
|---|---|
| Discovery | https://auth.example.com/.well-known/openid-configuration |
| Authorization | https://auth.example.com/authorize |
| Token | https://auth.example.com/oauth/token |
| Userinfo | https://auth.example.com/userinfo |
| JWKS (public keys) | https://auth.example.com/keys |
| Issuer | https://auth.example.com |
Apps that support OIDC discovery only need the discovery URL - everything else auto-configures.
Supported flow
Section titled “Supported flow”Authorization code + PKCE only. Implicit flow and client credentials are not supported.
Supported scopes
Section titled “Supported scopes”| Scope | Claims returned |
|---|---|
openid | sub (user ID) |
profile | preferred_username (email) |
email | email, email_verified |
offline_access | Enables refresh tokens |
Registering a client
Section titled “Registering a client”- Go to
/admin/clientsand click New client - Enter a display name and optionally an icon URL (fetched and cached server-side at save time)
- Choose a client ID - lowercase, digits, dashes. Public and permanent.
- Click Generate for the client secret. Copy it - it is not shown again.
- Enter redirect URIs one per line. Must match exactly.
Configuring an app
Section titled “Configuring an app”Most apps work with just the discovery URL, client ID, and client secret:
Discovery URL: https://auth.example.com/.well-known/openid-configurationClient ID: your-client-idClient Secret: your-client-secretScopes: openid email profilePython (authlib)
Section titled “Python (authlib)”from authlib.integrations.flask_client import OAuthoauth = OAuth(app)oauth.register( name='gatekeeper', server_metadata_url='https://auth.example.com/.well-known/openid-configuration', client_id='myapp', client_secret='your-client-secret', client_kwargs={'scope': 'openid email profile'},)Go (go-oidc)
Section titled “Go (go-oidc)”provider, _ := oidc.NewProvider(ctx, "https://auth.example.com")config := oauth2.Config{ ClientID: "myapp", ClientSecret: "your-client-secret", Endpoint: provider.Endpoint(), RedirectURL: "https://myapp.example.com/callback", Scopes: []string{oidc.ScopeOpenID, "email", "profile"},}Login page branding
Section titled “Login page branding”When a user arrives via /authorize, the login page shows the client’s display name and icon. Direct /login access shows the GateKeeper logo.
Token lifetimes
Section titled “Token lifetimes”| Token | Lifetime |
|---|---|
| Access token | 15 minutes |
| Refresh token | 30 days |
| ID token | 15 minutes |
Key rotation
Section titled “Key rotation”Tokens are signed with RS256. Keys rotate every 30 days automatically. The previous key stays active so tokens issued just before rotation remain valid.
Trusted devices
Section titled “Trusted devices”After a user passes 2FA, a 30-day trusted device cookie skips 2FA on return logins from the same device. Works for both OIDC and ForwardAuth flows.