Skip to content

OIDC Settings

OpenID Connect (OIDC) lets your users sign in to Grimmory with the same account they use for all your other self-hosted apps. Instead of managing separate passwords, you delegate authentication to a central identity provider like Authentik, Keycloak, Authelia, or Pocket ID. Users click one button, authenticate once, and they’re in.

Grimmory’s OIDC implementation handles the entire token exchange on the server side using the Authorization Code flow with PKCE, so secrets never touch the browser. It also supports back-channel logout, automatic user provisioning, and group-based permission mapping, giving you a complete SSO solution that scales from a single household to a busy shared server.


The OIDC settings page starts with a simple choice: which login methods should be available?

Login Methods

Local Login is the built-in username/password system. It’s always on and cannot be fully disabled. Even if you switch entirely to OIDC, admins can still reach the local login form as a safety net (more on that in OIDC-Only Mode).

OIDC Login enables the “Sign in with <Provider>” button on the login page. Toggle this on once you’ve completed the provider configuration below.

You can run both methods side by side. Users who have both a local password and an OIDC identity can use either one. This is useful during a migration period or if some users prefer not to use SSO.


This is where you connect Grimmory to your identity provider. You’ll need to create a client/application in your provider first (the provider-specific guides walk through this), then enter the credentials here.

Provider Configuration
FieldWhat to enterNotes
Provider NameA human-readable name like Authentik or My SSOShown on the login button. Users see “Sign in with <this name>”.
Client IDThe client/application ID from your providerCopy this exactly from your provider’s dashboard.
Client SecretThe client secret, if your provider requires oneLeave empty for public clients (most common for self-hosted setups using PKCE). Only needed for confidential clients.
Issuer URIYour provider’s OIDC issuer URLGrimmory appends /.well-known/openid-configuration to this URL to auto-discover all endpoints.
ScopesSpace-separated list of OIDC scopesDefaults to openid profile email groups offline_access if left empty. For Microsoft Entra ID, use openid profile email offline_access (without groups).
Session DurationHow long OIDC sessions last (in hours)Leave on “System default” unless you want OIDC sessions to differ from local ones.

The issuer URI varies by provider. Here are common patterns:

ProviderIssuer URI Pattern
Authentikhttps://auth.example.com/application/o/<app-slug>/
Keycloakhttps://keycloak.example.com/realms/<realm-name>
Autheliahttps://auth.example.com
Pocket IDhttps://pocket-id.example.com

OIDC providers send user information as “claims” inside tokens. Different providers use different claim names for the same data. Claim mappings tell Grimmory which claim to read for each user field.

Grimmory FieldDefault ClaimWhat it does
Usernamepreferred_usernameBecomes the Grimmory username. This is what users see in the app, and it’s how Grimmory matches returning OIDC users to existing accounts.
EmailemailThe user’s email address. Used for notifications and email-to-device features.
Display NamenameShown in the UI as the user’s name. Falls back to the username if not provided.
GroupsgroupsA list of group names from the provider. Used for Group Mapping to automatically assign permissions.

Not sure what claim names your provider uses? Here’s a quick reference:

ProviderUsernameEmailDisplay NameGroups
Authentikpreferred_usernameemailnamegroups
Keycloakpreferred_usernameemailnamegroups (requires mapper)
Autheliapreferred_usernameemailnamegroups
Pocket IDpreferred_usernameemailnamegroups

Before saving, click Test Connection to make sure Grimmory can talk to your provider. The test runs a series of checks:

  • Discovery document reachable
  • Authorization, token, and JWKS endpoints present
  • Signing keys fetchable
  • Required scopes (openid, profile, email) supported
  • PKCE (S256) supported
  • End session endpoint available (needed for single logout)
  • Back-channel logout supported

Checks that pass show a green checkmark. Warnings (yellow) mean the feature will work but some optional capability isn’t available. Failures (red) must be fixed before OIDC will work.


Once you save your provider configuration, Grimmory shows a reference panel with the exact values you need to paste into your identity provider’s client settings. Each value has a copy button.

Provider Configuration Reference

These values are auto-generated based on your Grimmory instance URL. You don’t need to edit them; just copy them into your provider.

ValueWhere to put it in your providerExample
Redirect URIAllowed redirect URIs / Callback URLhttps://books.example.com/oauth2-callback
Post-Logout Redirect URIPost-logout redirect URIshttps://books.example.com/login
Back-Channel Logout URIBack-channel logout URLhttps://books.example.com/api/v1/auth/oidc/backchannel-logout
Required ScopesAllowed/assigned scopesopenid profile email offline_access
PKCE MethodPKCE code challenge methodS256
Grant TypeAllowed grant typesAuthorization Code

If you want all users to authenticate exclusively through your identity provider, with no password-based fallback.

OIDC-Only Mode

When you enable OIDC-Only Mode:

  1. The local login form disappears from the login page
  2. Non-admin users visiting /login are automatically redirected to the OIDC provider
  3. Users can only authenticate through your identity provider; there is no password fallback

This is ideal when you want your OIDC provider to be the single gatekeeper for access, handling MFA, conditional access policies, and account lifecycle centrally.

If your OIDC provider goes down or a misconfiguration locks everyone out:

Option 1: Use the admin backdoor URL:

https://books.example.com/login?local=true

Option 2: Disable OIDC entirely at the infrastructure level by adding an environment variable to your Docker Compose or system config:

services:
grimmory:
environment:
- FORCE_DISABLE_OIDC=true

Restart Grimmory. OIDC is now completely disabled regardless of database settings. Remove the variable once you’ve fixed the issue.


When someone logs in via OIDC for the first time, what should happen? User provisioning controls whether Grimmory creates the account automatically and what permissions it starts with.

User Provisioning

Enabled (recommended for most setups): Any user who successfully authenticates through your OIDC provider gets a Grimmory account automatically. No admin action needed. The account is created with the default permissions and library access you configure below.

Disabled: Users must be manually created in Grimmory before they can log in via OIDC. The admin creates the user with a username that exactly matches the OIDC username claim. Good for high-security environments where you want explicit approval for every user.

This setting matters when you’re migrating from local authentication to OIDC and you have existing users who already have reading progress, bookmarks, and shelves.

Enabled: When a user logs in via OIDC and a local account with the same username already exists, Grimmory automatically links the OIDC identity to that account. The user keeps everything: reading progress, bookmarks, shelves, permissions, library access. The account is upgraded to OIDC authentication.

Disabled: Local accounts and OIDC accounts are kept separate. Only accounts originally created through OIDC (or already linked) can be matched.

Choose what newly provisioned users can do. These permissions are applied once when the account is created. You (or group mapping) can change them later.

Available default permissions:

PermissionWhat it allows
Read BooksView and read books (always granted)
Upload BooksAdd new books to libraries
Download BooksDownload book files
Edit Book MetadataModify book titles, authors, tags, etc.
Manage LibraryCreate, edit, and organize libraries
Email BookSend books to email/e-reader
Delete BookRemove books from libraries
KOReader SyncSync reading progress with KOReader devices
Kobo SyncSync books and progress with Kobo e-readers
Access OPDSBrowse books via OPDS catalog feeds

Select which libraries new users can access. Users only see books in their assigned libraries, so this controls their initial view of your collection. You can assign additional libraries per-user later.


Group mapping is the most powerful feature of Grimmory’s OIDC integration. It lets you define permission sets in your identity provider using groups, and Grimmory automatically applies the right permissions and library access based on which groups a user belongs to.

Instead of manually configuring each user’s permissions in Grimmory, you manage everything in your identity provider. Move a user to a different group in Authentik or Keycloak, and their Grimmory access updates on next login.

Group Mapping

The sync mode determines how group mappings are applied on each login.

ModeWhat happens on each loginBest for
DisabledNothing. Group mappings exist but aren’t applied.When you want to define mappings in advance but aren’t ready to use them yet.
On Login (Replace)The user’s permissions and libraries are completely replaced by what their group mappings define. Any manual changes made in Grimmory are overwritten.Setups where the identity provider is the single source of truth for access control. Most common choice.
On Login (Additive)Group-mapped permissions are added on top of existing permissions. Nothing is ever removed.Mixed environments where some permissions are managed via groups and others are granted manually in Grimmory.

Click Add Mapping to define a new mapping. Each mapping links an OIDC group to a set of Grimmory permissions.

FieldWhat to enterExample
Group ClaimThe exact group name as it appears in the OIDC token’s groups claim. Case-sensitive.grimmory-admins
AdminCheck this to grant full admin access to users in this group.
PermissionsSelect which permissions to grant.Read, Download, Upload
LibrariesSelect which libraries this group can access.Main Library, Comics
DescriptionAn optional note for your own reference.Full admin access

Users often belong to multiple groups. Grimmory handles this by merging all matching group mappings together:

Example: Sarah belongs to two groups in Authentik: grimmory-readers and grimmory-uploaders.

GroupPermissionsLibraries
grimmory-readersRead, DownloadFiction, Non-Fiction
grimmory-uploadersRead, UploadFiction, Staging

Sarah receives the union of both mappings:

  • Permissions: Read, Download, Upload
  • Libraries: Fiction, Non-Fiction, Staging

If any matching group has the Admin flag checked, the user becomes an admin.

For group mapping to work, your OIDC provider must include group names in the token. Here’s how to enable this for common providers:

Groups are included automatically in the groups claim. No extra configuration needed. Set the Groups Claim in Grimmory to groups.

Groups are not included by default. You need to add a mapper:

  1. Go to your Keycloak realm > Client Scopes > grimmory-dedicated (or your client’s scope)
  2. Click Add mapper > By configuration > Group Membership
  3. Set:
    • Name: groups
    • Token Claim Name: groups
    • Full group path: OFF (so you get my-group instead of /parent/my-group)
  4. Save

Set the Groups Claim in Grimmory to groups.

Add groups to your client’s scopes in the Authelia configuration:

identity_providers:
oidc:
clients:
- client_id: grimmory
scopes:
- openid
- profile
- email
- groups

Set the Groups Claim in Grimmory to groups.


A home server with a few family members. You just want everyone to sign in with one click.

What to configure:

  • Provider: Pocket ID (lightweight, easy to set up)
  • Auto Provisioning: Enabled
  • Link Local Accounts: Enabled (if migrating from passwords)
  • Default Permissions: Read, Download
  • Default Libraries: Family Library
  • OIDC-Only Mode: Disabled (keep password login as backup)
  • Group Mapping: Disabled (not needed for a few users)

Grimmory settings:

SettingValue
Provider NamePocket ID
Client IDgrimmory
Client Secret(empty)
Issuer URIhttps://pocket-id.home.lan
Scopeopenid profile email offline_access

Docker Compose snippet:

services:
grimmory:
image: grimmory/grimmory:latest
ports:
- "8080:8080"
volumes:
- ./data:/data
- /mnt/books:/books

That’s it. No special environment variables needed. Configure OIDC in the admin UI, and family members can sign in with Pocket ID.


A homelab with 10-20 users, several libraries (Fiction, Non-Fiction, Comics, Audiobooks), and different access levels. You manage users centrally in Authentik.

What to configure:

  • Provider: Authentik
  • Auto Provisioning: Enabled
  • Link Local Accounts: Enabled initially, disable after migration
  • Default Permissions: Read only (group mapping handles the rest)
  • OIDC-Only Mode: Enabled (everyone uses Authentik)
  • Group Sync Mode: On Login (Replace)

Group mappings:

Group ClaimAdminPermissionsLibrariesDescription
grimmory-adminsYesRead(all)Server admins
grimmory-power-usersNoRead, Download, Upload, Edit Metadata, KOReader Sync, Kobo Sync, OPDSFiction, Non-Fiction, Comics, AudiobooksTrusted users with full access
grimmory-readersNoRead, Download, OPDSFiction, Non-FictionRegular readers
grimmory-kidsNoReadKids LibraryChildren’s accounts

How it works in practice:

  1. You create these groups in Authentik and assign users to them
  2. When a new user (let’s say “Alex”) logs into Grimmory for the first time via Authentik, Grimmory auto-creates their account
  3. Alex is in the grimmory-readers group, so they get Read + Download + OPDS access to Fiction and Non-Fiction
  4. Later, you move Alex to grimmory-power-users in Authentik
  5. Next time Alex logs in, Grimmory automatically upgrades their permissions and grants access to Comics and Audiobooks
  6. No manual Grimmory admin work needed

Locked-Down Setup: Confidential Client, No Auto-Provisioning

Section titled “Locked-Down Setup: Confidential Client, No Auto-Provisioning”

A shared server where you want tight control over who gets access. All authentication goes through Keycloak with a confidential client, and users must be pre-approved.

What to configure:

  • Provider: Keycloak (confidential client)
  • Auto Provisioning: Disabled (users must be pre-approved)
  • OIDC-Only Mode: Enabled
  • Group Sync Mode: On Login (Replace)
  • Session Duration: 8 hours

Grimmory settings:

SettingValue
Provider NameKeycloak
Client IDgrimmory-prod
Client Secreta1b2c3d4-e5f6-7890-abcd-ef1234567890
Issuer URIhttps://keycloak.example.com/realms/myrealm
Scopeopenid profile email offline_access
Session Duration8

Group mappings:

Group ClaimAdminPermissionsLibrariesDescription
grimmory-adminsYesReadAllServer admins
grimmory-usersNoRead, DownloadMain Library, SharedStandard user access
grimmory-curatorsNoRead, Download, Upload, Edit Metadata, Email BookMain Library, Shared, StagingCurators who manage the collection

Docker Compose snippet:

services:
grimmory:
image: grimmory/grimmory:latest
ports:
- "8080:8080"
volumes:
- ./data:/data
- /mnt/books:/books

New users are created manually in Grimmory by an admin (auto provisioning is off), but their permissions are managed entirely through Keycloak groups.


Understanding what happens behind the scenes helps when troubleshooting. Here’s the complete flow when a user clicks “Sign in with <Provider>”:

  1. User clicks the OIDC login button on the Grimmory login page

  2. Grimmory generates security parameters: A random state token (stored server-side for CSRF protection), a PKCE code verifier and challenge (stored in the browser’s session storage), and a nonce

  3. Browser redirects to the identity provider with the authorization request, including the code challenge, state, nonce, and requested scopes

  4. User authenticates with the provider (password, MFA, biometrics, whatever the provider requires)

  5. Provider redirects back to Grimmory with an authorization code and the original state

  6. Grimmory’s backend exchanges the code for tokens by calling the provider’s token endpoint directly (server-to-server). This is where the code verifier proves the request came from the same session that started the flow. If a client secret is configured, it’s sent here too.

  7. Backend validates the ID token: Checks the signature against the provider’s public keys (JWKS), verifies the issuer, audience, expiration, nonce, and other security claims

  8. Backend extracts user information from the token claims and optionally the userinfo endpoint

  9. User is matched or created in Grimmory (based on provisioning settings)

  10. Group mappings are applied (if configured)

  11. Grimmory issues its own session tokens and the user is logged in

The entire token exchange happens on the server. The browser never sees the OIDC access token, refresh token, or ID token.


  • OIDC Login must be toggled on in Login Methods
  • Provider Name, Client ID, and Issuer URI must all be filled in and saved
  • If you just saved settings, refresh the login page
  • The Issuer URI must be reachable from the Grimmory server (not from your browser). If running in Docker, use the container network name or ensure the container can reach the external URL.
  • Try curling the discovery endpoint from the Grimmory server:
    Terminal window
    curl https://auth.example.com/application/o/grimmory/.well-known/openid-configuration
  • Check for trailing slash issues. Some providers require a trailing slash, others don’t.

Login Redirects to Provider But Comes Back with an Error

Section titled “Login Redirects to Provider But Comes Back with an Error”
  • Redirect URI mismatch: The redirect URI configured in your provider must exactly match what Grimmory generates. Copy it from the Provider Configuration Reference panel. Common mistakes: missing /oauth2-callback path, wrong port, http vs https.
  • Scopes not allowed: Make sure openid, profile, email, and offline_access are all enabled in your provider’s client configuration.
  • Wrong Client ID or Secret: Double-check these values. A single extra space can cause a failure.
  • Check Grimmory application logs (docker logs grimmory) for a specific error message.

User Logs In But Gets “User Not Provisioned”

Section titled “User Logs In But Gets “User Not Provisioned””

This means auto-provisioning is disabled and no Grimmory account matches the OIDC username. Either:

  • Enable auto-provisioning, or
  • Manually create a Grimmory account with a username that exactly matches the OIDC preferred_username claim (case-sensitive)
  1. Is the Groups Claim configured? Check the Claim Mappings section. The default is groups.
  2. Does your provider actually send groups? Not all providers do by default. See the provider-specific instructions above.
  3. Is Group Sync Mode enabled? It defaults to Disabled. Set it to On Login (Replace) or On Login (Additive).
  4. Do group names match exactly? Group claim values are case-sensitive. Grimmory-Admins is not the same as grimmory-admins. Check what your provider actually sends by inspecting the token (most providers have a token preview feature).

Sessions Not Syncing (User Stays Logged In After Provider Logout)

Section titled “Sessions Not Syncing (User Stays Logged In After Provider Logout)”
  • Back-channel logout must be configured in your provider. Copy the Back-Channel Logout URI from the reference panel.
  • The logout URI must be reachable from the provider’s server, not from the browser. If they’re on the same Docker network, use the internal hostname.
  • Not all providers support back-channel logout. If yours doesn’t, users will stay logged in to Grimmory until their session expires naturally.

Two escape hatches:

  1. Admin backdoor URL: https://books.example.com/login?local=true
  2. Environment variable override: Add FORCE_DISABLE_OIDC=true to your Docker Compose and restart

If OIDC-Only Mode is enabled and the provider keeps bouncing back with errors, Grimmory has built-in loop protection. After 3 failed redirect attempts, it stops auto-redirecting and shows an error message on the login page with a link to the local login form.