Single sign-on with OpenID Connect

People can now sign in to Specivo with the account they already have at your identity provider. Specivo is an OpenID Connect client, so Keycloak, authentik, Microsoft Entra ID and any other provider that publishes a discovery document work. You set it up under Administration → Single sign-on, and it stays off until you add a provider.

We tested it end to end with Keycloak and authentik. Entra ID has a full setup page of its own. Okta, Google, Zitadel and Authelia have short notes that have not been walked through screen by screen, so check each setting against your provider's current documentation and use the connection test in Specivo. The single sign-on guide explains every setting, and there are pages for Keycloak, authentik, Microsoft Entra ID and the other providers.

What you get:

  • Several providers at once. Each one gets its own button on the login page, a connection test, and a client secret that is stored encrypted. A secret can also be read from a SPECIVO_SSO_SECRET_* environment variable instead.
  • Accounts on first sign-in. Specivo can create an account the first time someone signs in. People with an existing account can connect it from Profile → Connected accounts, and you can allow automatic linking by verified email. All three are off by default.
  • Group mapping. Groups at the identity provider can map to Specivo user groups and to the administrator flag. Each provider can also require certain groups, and limit sign-in to a list of email domains.
  • Sign-out that follows the provider. Signing out of Specivo can sign you out at the provider. With back-channel logout turned on, a session ended at the provider ends in Specivo too.
  • Login page options. Show provider buttons, hide the password form, redirect straight to one provider, or keep password sign-in for administrators only.
  • Audit events for sign-in, account linking, group changes, logout and provider changes. A new sessions list under Preferences → Security shows how each session signed in.

Under the hood, Specivo uses the authorization code flow with PKCE (S256), state and nonce for every provider. Service accounts, the ones AI agents use, can never sign in through single sign-on, and API keys are not affected by it.

Local accounts keep working. If you lock yourself out with a login page setting, ?local=1 on the login URL and the SSO_FORCE_LOCAL_LOGIN setting are the way back in. Keep an administrator with a password while you test.

Single sign-on is OpenID Connect only. SAML is not supported, and there is no SCIM or LDAP directory sync: people appear when they first sign in. The guide has an offboarding section for removing access.

Deactivating users

Administrators can now deactivate and reactivate users from the user's page. Deactivating ends every session and switches off the user's API keys. Reactivating does not switch the keys back on, so you decide which ones come back.

Signing out, passwords and API keys

Several things around sessions changed, mostly for the better, and a few need a look if you script against Specivo.

  • Sign out is a form. Opening /logout/ from a bookmark or link now asks "Sign out?" first. POST /api/v1/auth/logout/ returns 200 with an end_session_url instead of 204. The value is null unless the session came from a provider that supports signing out there.
  • Signing out really signs out. Before, the server-side session and the access token stayed valid until they expired. Now both end at once.
  • A password reset ends every session of the account, whether it was done by email, by an administrator or from the command line. People who sign in only through single sign-on cannot reset a password by email.
  • Administrator API keys do less. They are refused with 403 for password resets, unlocking or reactivating users, creating people or administrators, issuing keys for other users and changing single sign-on settings. Service accounts can still be created. Automation that did any of this with a key has to run as a signed-in administrator.

Client addresses behind a proxy

Specivo now reads the client address from X-Forwarded-For only when the request comes through a proxy listed in TRUSTED_PROXIES. TRUSTED_PROXY_HOPS says how many proxies stand in a row, and defaults to 1. This also fixes every client behind the bundled nginx sharing one rate-limit bucket, and it means the audit log shows the real address. The bundled nginx access log no longer includes query strings, which can carry the code and state of a single sign-on sign-in.

Security fixes

  • Requests that carried only the refresh cookie skipped the CSRF check.
  • A token refresh could race a session revocation and keep the session alive.
  • Sign-out left the server-side session and the access token valid until they expired. See above.

Smaller changes

  • The unused github_id and google_id columns are removed from the users table.

What to do when upgrading

Back up your database and data directory first. The upgrade applies three migrations (0041 to 0043) on startup. Nothing needs configuring to keep working as before, and people who are signed in stay signed in.

  • The bundled stack gets a proxy network. Take the new docker-compose.yml: nginx sits at a fixed address on that network so Specivo can trust exactly that address. If docker compose up -d stops with "Pool overlaps", set SPECIVO_PROXY_SUBNET and SPECIVO_NGINX_IP in .env to a free range and address.
  • Keep your own Compose file or nginx config? Add the network the same way or set TRUSTED_PROXIES to your proxy's address. With TRUSTED_PROXIES empty, everyone behind a proxy shares one address. If another proxy sits in front of the bundled nginx, set TRUSTED_PROXY_HOPS=2. A custom nginx/default.conf must keep proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;.
  • If you turn on single sign-on, set APP_URL first. The redirect and logout addresses are built from it.
  • Rotating SECRET_KEY now also means re-entering SSO client secrets, because they are encrypted with a key derived from it. Back up .env.local together with the database dump.
  • Scripts that expect 204 from sign-out must accept 200, and automation that uses an administrator's API key for the actions listed above has to change.

The upgrading guide has the full details.

How to get it

Pull the Docker image with docker pull specivo/specivo:0.10.0. For servers without internet access, the GitHub Release includes an offline bundle. For installation and upgrade steps, see the user guide.