Skip to content

Enterprise single sign-on

Any organization owner can connect an OpenID Connect identity provider (Okta, Entra ID, Keycloak, Google Workspace, and the rest) from the organization’s SSO tab, with no operator involved. People who sign in through the connection become members of your organization, joining as readers.

Setup has two independent tiers, so nothing blocks on DNS:

  1. The connection. It works the moment it is created, through its direct sign-in link. Create it, test it, share the link inside your company; no domain proof is involved.
  2. Email routing. Typing an email on the shared sign-in page routes to your provider only for domains you claim on the connection and verify with a domain-ownership proof. The proof is re-checked at every sign-in, so a lapsed proof stops routing until it recovers.

Register a confidential OIDC client (a “web application”) with your provider:

  • Redirect URI: https://your-haven-instance/auth/callback (the SSO tab shows the exact value to copy).
  • Grant: authorization code. Haven uses PKCE and validates the id_token against the provider’s published signing keys.
  • Scopes: the connection requests openid email profile unless you configure others.

Note the client ID and client secret; Haven needs both. The client secret is stored encrypted and is write-only: no Haven response ever contains it.

On the SSO tab, enter a name, the issuer URL, and the client credentials. The issuer is the base URL that serves /.well-known/openid-configuration; for a Keycloak realm that is https://idp.example.com/realms/your-realm.

Two optional fields:

  • Link name: the short name inside the connection’s sign-in link, defaulting to your organization’s name. It cannot be changed later; it identifies the connection on sign-in links and on the sessions it minted.
  • Internal issuer URL: only for split-horizon deployments where Haven must reach the provider on a different address than the public issuer. The provider’s configuration must still name the public issuer. The field only exists on self-hosted deployments whose operator has set allow_private_upstreams; everywhere else Haven reaches the provider at its issuer URL, and the API refuses the field.

Check configuration fetches the provider’s OIDC configuration through the same path sign-ins use and reports what it found: the authorization, token, and signing-key endpoints, and whether the document names the issuer you configured. It cannot test the client secret.

The full round-trip test is the direct sign-in link on the connection’s card: open it in a private window and sign in. It exercises the redirect, the token exchange (and so the secret), and the id_token validation end to end. This link is also the everyday sign-in path before email routing is on: bookmark it, put it on your intranet, or share it in your onboarding docs.

Claim your email domains on the connection, then verify each one in the Domains tab. Once a claimed domain is verified, anyone typing a matching email on the shared sign-in page is routed to your provider. The SSO tab shows each domain’s routing status, and routing follows the proof: if it lapses, routing stops; when it recovers, routing resumes.

A claim without a proof is inert but not useless: it reserves your intent, and it cannot be squatted against you. If another organization claimed your domain without a proof, your verified proof takes the claim over. An organization’s connections can claim at most 20 domains in total, the same ceiling as domain-ownership proofs.

Verification also unlocks invite auto-accept: pending invites to your organization are accepted automatically when the invited person signs in through your connection asserting an email under the proven domain, landing them at the invited role instead of the default reader. This never extends to other organizations’ invites.

Everything except the link name can be edited in place: label, issuer, client ID, scopes, and the internal issuer. Rotating the client secret is an edit too; leave the field blank to keep the current one. Every change is recorded in the audit log.

Deleting a connection stops its sign-ins immediately, direct link included, and releases its domain claims. Sessions it already minted stay signed in until they expire or sign out.

  • “issuer rejected” when saving: Haven fetches the issuer server-side and refuses private, loopback, and link-local addresses. On self-hosted deployments whose IdP lives on a private network, the operator can set allow_private_upstreams in the instance configuration.
  • Check configuration reports an issuer mismatch: the provider’s configuration document names a different issuer than the one you entered. Sign-in fails until they match; usually the issuer URL has a typo or points at the wrong realm or tenant.
  • The provider rejects the redirect: the redirect URI registered with your provider must exactly match the one the SSO tab shows.
  • Emails stopped routing to the provider: the domain proof has lapsed. Open the Domains tab, restore the record, and press Check now; routing resumes with the proof. The direct link keeps working throughout.