Manual
CLI
API
Log in Get started free

Single sign-on

Sets up OpenID Connect sign-in for the organisation: the identity provider, the domains it covers and whether passwords are still allowed.

Members of an organisation can sign in through its own identity provider (Okta, Microsoft Entra ID, Google Workspace, Keycloak, or any provider that supports OpenID Connect) instead of a password. Single sign-on is a Business plan feature.

Access: Session token only. API keys get 403 with insufficient_scope.

Role: Organisation owner or admin, for the routes under /org/sso.

Set up #

  1. In your identity provider, create an OpenID Connect web application. Use the redirectUri from GET /org/sso as its redirect URI, and note the client id and client secret.
  2. Add and verify every email domain your members use.
  3. Save the provider with PUT /org/sso.
HTTP
GET /org/sso
PUT /org/sso

PUT takes:

FieldTypeDescription
issuerstringThe issuer URL of the provider. We read <issuer>/.well-known/openid-configuration. It must use https.
clientIdstringThe client id.
clientSecretstringThe client secret. Leave it out to keep the stored one. It is stored encrypted and never returned.
enabledbooleanTurn sign-in on. Needs at least one verified domain and a reachable provider.
enforcebooleanMembers can no longer sign in with a password. Owners always can, so you cannot lock yourself out. Needs enabled.
autoProvisionbooleanCreate an account and membership the first time someone from a verified domain signs in. Default true. When off, only existing members can sign in.
defaultRolestringmember (default) or admin: the role of people created by autoProvision.

Both answer 200 with the settings: the fields above (without clientSecret, with clientSecretSet), domains, pendingDomains, redirectUri and available, which says whether the plan includes single sign-on.

The organisation’s two-factor requirement does not apply to single sign-on: your identity provider decides how people prove who they are.

Domains #

Only people whose email address is on a verified domain can sign in, and a domain can belong to one organisation.

HTTP
POST /org/sso/domains
POST /org/sso/domains/{domain}/verify
DELETE /org/sso/domains/{domain}

POST /org/sso/domains takes {"domain": "example.com"} and returns the settings, where pendingDomains holds the DNS record to publish:

JSON
{"pendingDomains": {"example.com": {"record": "_continuous-translations.example.com", "value": "ct-domain-verification=3f9c…"}}}

Add that value as a TXT record on that name, then call verify. It answers 422 with domain_not_verified until the record is visible, and 409 with domain_taken if another organisation verified the domain first. Removing the last domain turns single sign-on off.

Signing in #

These two routes need no token. The editor calls them; they are documented for people building their own client.

HTTP
POST /auth/sso/discover
POST /auth/sso/start
POST /auth/sso/callback

discover takes email and answers {"sso": true} when the address is on a domain whose organisation has single sign-on turned on, and {"sso": false} otherwise. The editor’s sign-in form uses it to ask for a password or not.

start takes email and binding, a random string of at least 16 characters that the browser keeps (for example in session storage). It answers {"url": "…"}: send the browser there. The provider redirects back to the redirectUri with code and state; send those and the same binding to callback, which answers like POST /auth/login with a token, expiresAt and user. The binding makes sure only the browser that started the sign-in can finish it.

Audit log #

Setting changes record org.sso_changed, org.sso_domain_verified and org.sso_domain_removed; each sign-in records auth.sso_login; a member created on first sign-in also records org.member_joined.

Errors #

StatuserrorWhen
400invalid_stateThe state is forged, expired (10 minutes) or was started in another browser.
401sso_failedThe provider refused the code, or the ID token’s issuer, audience, expiry or nonce is wrong.
402plan_limitThe plan does not include single sign-on.
403email_not_verifiedThe provider says the email address is not verified.
403domain_not_allowedThe email address is not on a verified domain.
403not_a_memberautoProvision is off and the person is not a member.
403sso_required(POST /auth/login) The organisation requires single sign-on.
404sso_not_configuredNo organisation with single sign-on owns the email’s domain.
422invalid_requestA field is invalid; fields.issuer is invalid, unreachable or not_openid, and fields.sso is incomplete or no_verified_domain.

See Errors for the error format.