Skip to content

Single sign-on

If your household or organization already has a sign-in service, people can use it for Savorum instead of a separate password. Savorum supports OpenID Connect (OIDC), LDAP and Active Directory, a trusted reverse proxy, and SAML 2.0. Each person still gets a full Savorum account that owns their libraries and recipes.

  1. List your providers in a JSON file, using the examples below. Keep passwords, client secrets, and keys in separate files that it refers to, readable only by the Savorum service account.

  2. Point Savorum at the file, with --auth-providers-file or SAVORUM_AUTH_PROVIDERS_FILE:

    Terminal window
    savorum serve --database /var/lib/savorum/savorum.db \
    --auth-enabled --public-url https://recipes.example.com \
    --auth-providers-file /etc/savorum/providers.json
  3. Restart Savorum whenever you change the file.

Every provider has an ID, such as company-oidc. Choose it once and keep it. Use a new ID when the sign-in service itself changes, and never reuse an old ID for a different organization. local, passkey, recovery, token, and system are reserved.

Every provider also accepts:

  • auto_provision: creates an account the first time someone new signs in. Off by default. Accounts are never merged because their emails match.
  • default_library and default_role (viewer or editor): give new accounts a starting membership.
  • allow_local_recovery: true: lets people who sign in only through this provider create recovery codes. Off by default.

Without automatic accounts, a person needs an invitation, or must link the provider to their existing account under Your account → Sign-in and security.

{
"providers": [
{
"id": "company-oidc",
"kind": "oidc",
"display_name": "Company account",
"auto_provision": true,
"default_library": "YOUR_LIBRARY_ID",
"default_role": "viewer",
"oidc": {
"issuer": "https://identity.example.com/realms/company",
"client_id": "savorum",
"client_secret_file": "/run/secrets/savorum-oidc-client",
"groups_claim_path": "organization.groups"
}
}
]
}

Register this exact redirect URI with the provider:

https://recipes.example.com/api/v1/auth/company-oidc/callback

Savorum asks for openid profile email, plus anything you list in scopes. Set groups_claim_path, a dot-separated path, only if the provider puts a trustworthy list of groups in its ID token. A missing claim means no groups. A malformed claim fails sign-in.

{
"providers": [
{
"id": "directory",
"kind": "ldap",
"display_name": "Directory account",
"auto_provision": true,
"ldap": {
"url": "ldaps://directory.example.com:636",
"bind_dn": "cn=savorum-search,ou=Services,dc=example,dc=com",
"bind_password_file": "/run/secrets/savorum-ldap-search",
"user_base": "ou=People,dc=example,dc=com",
"login_attribute": "uid",
"id_attribute": "entryUUID",
"display_attribute": "cn",
"email_attribute": "mail",
"group_attribute": "memberOf",
"required_groups": ["cn=recipe-users,ou=Groups,dc=example,dc=com"]
}
}
]
}

Use ldaps:// for TLS from the start, or ldap:// for StartTLS, which is then required. Certificates are checked normally, so put a private CA certificate in the operating system’s trust store. For anonymous search, leave out bind_dn and bind_password_file.

id_attribute must never change for a person and must hold a single value. Never use a DN, login name, or email attribute. Standard directories usually use entryUUID. For Active Directory, use objectGUID, with sAMAccountName or userPrincipalName as login_attribute.

required_groups lets someone sign in only if at least one listed group appears in group_attribute. Groups match as exact text, so list the full group DNs.

Use this when a gateway in front of Savorum already signs people in and passes on who they are in a header.

{
"providers": [
{
"id": "gateway",
"kind": "proxy",
"display_name": "Gateway account",
"auto_provision": true,
"proxy": {
"trusted_peers": ["192.0.2.10/32"],
"subject_header": "Remote-User-ID",
"display_header": "Remote-Name",
"email_header": "Remote-Email",
"strict": true
}
}
]
}

The proxy must remove or overwrite any identity headers the client sends, then set its own. Never only add the header when it’s missing, or anyone can sign in as anyone. Where you can, firewall Savorum so only the gateway can reach it.

Keep strict at its default, true. It refuses every request that doesn’t come from a trusted peer, except /api/v1/health. Let /calendar/ through the gateway without sign-in, because calendar apps can’t sign in; the link is the credential.

If the proxy also forwards the scheme, host, or client address, list it with --trusted-proxy too. That flag alone never makes Savorum trust identity headers. See Secure remote access.

A gateway sign-in starts a normal Savorum session, and the header isn’t checked again. To remove someone at once, disable their Savorum account or revoke their sessions.

Use OIDC where you can. For services that require SAML:

{
"providers": [
{
"id": "corporate-saml",
"kind": "saml",
"display_name": "Corporate SSO",
"auto_provision": false,
"saml": {
"metadata_url": "https://identity.example.com/saml/metadata",
"certificate_file": "/etc/savorum/saml-sp.crt",
"private_key_file": "/run/secrets/savorum-saml-sp-key",
"display_attribute": "displayName",
"email_attribute": "mail",
"groups_attribute": "memberOf"
}
}
]
}

Savorum needs its own RSA certificate and private key. Give the identity provider these two addresses. The metadata URL is also Savorum’s entity ID.

https://recipes.example.com/api/v1/auth/corporate-saml/metadata
https://recipes.example.com/api/v1/auth/corporate-saml/acs

Load the identity provider’s metadata from metadata_url over HTTPS, or from a local file with metadata_file. Expired metadata fails sign-in. Changing the identity provider’s entity ID needs a new provider ID.

A persistent NameID is required by default. Set subject_attribute only to an attribute that never changes for a person. Using an email as the subject also needs allow_mutable_subject: true, and an email change then creates a new identity that can lock the person out. Sign-in must start from Savorum: sign-in started at the identity provider, and SAML single logout, aren’t supported.

OIDC, LDAP, and SAML providers can pass a person’s groups to Savorum. To turn a group into a library role:

  1. Open Instance administration → Sign-in providers.
  2. Choose the provider and enter the group exactly as the provider sends it.
  3. Choose a library and a role.

Each rule grants one membership. The same group name from a different provider grants nothing. When a group disappears, only that rule’s membership goes. Manual memberships and other rules stay, and the highest role applies.

Removing someone from a group doesn’t end their access until they sign in again. To remove someone at once, disable their Savorum account or revoke their sessions.

Sign in through the provider with an account that isn’t an administrator, and check that it gets only the library memberships you intended.

  • Removing or disabling a provider takes effect at the next restart. It ends that provider’s browser sessions and removes the memberships it granted. Accounts, manually granted memberships, and other sign-in methods stay.
  • Tokens created while signed in through a provider stop working when that provider is disabled.

Next: Maintain storage and integrity.