Single sign-on API
Ce contenu n’est pas encore disponible dans votre langue.
Most administrators set up single sign-on in Settings → Single sign-on, which calls these same endpoints; see Single sign-on. This page is for scripting the configuration and for security reviews.
Before you start
Section titled “Before you start”Who can call them. The settings endpoints need a signed-in person with the sso.manage
permission (by default, the Administrator). An API key gets 401 sign in required. Every change is written to the
audit log.
Signing in with curl. Sign in once and keep the session cookie, as described in
Alerts and cases API: before you start. Then add
-b ~/.sp-cookies to every request below.
Endpoints at a glance
Section titled “Endpoints at a glance”Settings (sso.manage):
| Endpoint | Does | Success |
|---|---|---|
GET /api/v1/settings/sso |
The settings, SpeculaPro’s values for the IdP, domains and break-glass administrators. Never the client secret | 200 |
PUT /api/v1/settings/sso |
Replace the settings. Checks the connection first | 200 with the new settings |
POST /api/v1/settings/sso/metadata/refresh |
Fetch the SAML IdP metadata from its URL now | 200 with the settings |
POST /api/v1/settings/sso/domains |
Claim an email domain | 201 with the domain, or 202 when sent for approval |
POST /api/v1/settings/sso/domains/{id}/verify |
Look for the domain’s DNS TXT record. Never needs approval | 200 with the domain |
DELETE /api/v1/settings/sso/domains/{id} |
Stop routing a domain to SSO | 204, or 202 when sent for approval |
PUT /api/v1/settings/sso/break-glass |
Replace the list of break-glass administrators | 200 with the settings |
POST /api/v1/settings/sso/test |
Start a connection test; open redirect_url in a popup |
200 {"redirect_url": …} |
GET /api/v1/settings/sso/test/{id} |
A test’s result, for the administrator who ran it, for 10 minutes | 200 |
GET /api/v1/settings/sso/scim, POST …/scim/tokens, DELETE …/scim/tokens/{id} |
SCIM provisioning: the base URL and its tokens | See the SCIM API |
GET /api/v1/settings/sso and GET /api/v1/settings/sso/scim also answer for settings.view
(the Auditor), read-only and never with a secret.
Sign-in (no session needed; used by the sign-in page and the IdP):
| Endpoint | Does |
|---|---|
GET /api/v1/auth/sso/workspace?workspace=<slug> |
{"sso": …, "required": …, "protocol": …}: whether to offer SSO. An unknown workspace answers like one without SSO |
POST /api/v1/auth/sso/start |
Body {"workspace", "email"?, "return_to"?}. Returns {"redirect_url"} and sets the browser-binding cookie. 404 when SSO isn’t offered for the workspace or the email’s domain |
GET /api/v1/auth/sso/oidc/callback |
The OIDC redirect URI |
POST /api/v1/auth/sso/saml/{workspace}/acs |
The SAML ACS URL. Stashes the response and redirects to …/finish |
GET /api/v1/auth/sso/saml/{workspace}/finish |
Validates the stashed response for this browser |
GET /api/v1/auth/sso/saml/{workspace}/metadata |
SpeculaPro’s SP metadata for the workspace (also its SAML entity ID), including the single logout URL. 404 unless the workspace uses SAML |
GET, POST /api/v1/auth/sso/saml/{workspace}/slo |
The SAML single logout URL. Takes the IdP’s signed LogoutRequest (HTTP-Redirect or HTTP-POST), ends the sessions it names and answers the IdP with a signed LogoutResponse; also where the IdP returns the browser after a sign-out started in SpeculaPro. Needs no session cookie. A refused request answers 400 with a reference |
GET /api/v1/auth/sso/saml/{workspace}/slo/request?k=<key> |
For an IdP that takes logout requests only by HTTP-POST: a page that posts the signed LogoutRequest prepared at sign-out to the IdP. The web app sends the browser here when sign-out returns this address as sso_logout_url. The key works once, for 2 minutes; an unknown, used or expired key redirects to /login. Needs no session cookie. 429 when rate limited |
POST /api/v1/auth/sso/totp |
Body {"code"}. Finishes an SSO sign-in that needs the person’s SpeculaPro authenticator code. It takes the authenticator’s code only, not a recovery code |
The browser endpoints answer with redirects. A failure goes to /login?sso_error=failed&ref=<request ID> (or sso_error=rate); the reason is in the audit log. How they are protected is in
Single sign-on security.
The settings object
Section titled “The settings object”GET returns, and PUT takes, this object. PUT replaces everything, so send the whole object.
| Field | Meaning |
|---|---|
enabled |
Offer SSO on the sign-in page |
protocol |
oidc or saml |
required |
Everyone signs in with SSO, except break-glass administrators. Needs enabled and a usable break-glass administrator |
oidc.issuer |
Issuer URL. Must be HTTPS |
oidc.client_id |
Client ID |
oidc.client_secret |
Write-only. Stored encrypted, never returned. Leave it out to keep the stored one |
oidc.has_client_secret |
Read-only: whether a secret is stored |
oidc.scopes |
Scopes to request; openid is always added. Default openid, email, profile |
oidc.require_email_verified |
Refuse ID tokens whose email_verified isn’t true. Default true |
saml.metadata_url |
IdP metadata URL, refreshed daily. Must be HTTPS |
saml.metadata_xml |
Write-only. Paste the IdP metadata instead (up to 500,000 characters); this clears metadata_url |
saml.idp_entity_id, saml.metadata_fetched_at |
Read-only: the IdP the metadata describes, and when it was last fetched from the URL |
saml.allow_idp_initiated |
Accept sign-ins started from the IdP’s portal. Default false |
saml.email_attribute, saml.name_attribute |
Attribute names to read; empty uses the common ones |
provisioning.jit |
Create accounts at first sign-in. Default false |
provisioning.groups_claim |
OIDC claim or SAML attribute that lists groups |
provisioning.role_mapping_enabled |
Set roles from groups at every sign-in |
provisioning.mappings |
[{"group": …, "role": …}], up to 200. role is a role key such as analyst or mlro. See Roles |
provisioning.default_role |
Role key when no group matches; empty for none |
provisioning.deny_if_no_mapping |
Refuse when no group matches. Default true |
mfa.require_idp_mfa |
Refuse sign-ins the IdP doesn’t mark as multi-factor |
mfa.values |
amr, acr and AuthnContextClassRef values that mean multi-factor, up to 50. Empty restores the defaults |
GET also returns:
| Field | Meaning |
|---|---|
sp.redirect_uri, sp.post_logout_redirect_uri |
For OIDC registration |
sp.entity_id, sp.acs_url, sp.slo_url, sp.metadata_url |
For SAML registration. sp.slo_url is the single logout URL |
domains |
Each claimed domain: id, domain, verified, verified_at, txt_name, txt_value, created_at |
break_glass |
Each break-glass administrator: id, email, display_name, status, has_password, totp, admin, and usable (active, can manage people, own password and two-factor) |
usable_break_glass |
How many are usable now |
domain_verification |
Whether domains need a DNS TXT record |
Change the settings
Section titled “Change the settings”PUT /api/v1/settings/sso
Section titled “PUT /api/v1/settings/sso”Before saving, SpeculaPro checks the connection: for OIDC with enabled, it reads the issuer’s
discovery document; for SAML, it parses pasted metadata, or saves and then fetches the metadata URL.
Turning required on for the first time ends everyone’s password sessions except break-glass
administrators’.
curl -s -b ~/.sp-cookies -X PUT -H 'Content-Type: application/json' \ -d '{ "enabled": true, "protocol": "oidc", "required": false, "oidc": {"issuer": "https://login.example.com", "client_id": "speculapro", "client_secret": "…", "scopes": ["openid", "email", "profile"], "require_email_verified": true}, "saml": {"metadata_url": "", "allow_idp_initiated": false, "email_attribute": "", "name_attribute": ""}, "provisioning": {"jit": false, "groups_claim": "groups", "role_mapping_enabled": true, "mappings": [{"group": "speculapro-analysts", "role": "analyst"}, {"group": "speculapro-mlro", "role": "mlro"}], "default_role": "", "deny_if_no_mapping": true}, "mfa": {"require_idp_mfa": false, "values": []} }' \ "$SP/api/v1/settings/sso"Domains
Section titled “Domains”POST /api/v1/settings/sso/domains
Section titled “POST /api/v1/settings/sso/domains”Body {"domain": "acmebank.com.gh"}. Where verification is required, the answer has
"verified": false and the record to create: txt_name is _speculapro-challenge.<domain> and
txt_value is speculapro-domain-verification=<code>. Without verification, the domain is verified at
once.
Claiming and removing a domain are single sign-on changes (sso.config). Where the workspace
requires approval for them, send X-Change-Reason: the answer is 202
with the change request, and the TXT record is in the request’s result once it is approved. Only
one claim of the same domain can wait at a time.
POST /api/v1/settings/sso/domains/{id}/verify
Section titled “POST /api/v1/settings/sso/domains/{id}/verify”Looks the TXT record up (5-second timeout) and marks the domain verified when the value matches. If it
isn’t found yet, 422.
Break-glass administrators
Section titled “Break-glass administrators”PUT /api/v1/settings/sso/break-glass
Section titled “PUT /api/v1/settings/sso/break-glass”Body {"user_ids": ["…", "…"]}, up to 20. Replaces the list. Each must hold a role that can manage
people. While SSO is required, a list with no usable administrator is refused with 409.
Errors
Section titled “Errors”| Status | Meaning | Examples |
|---|---|---|
401 |
Not signed in, or an API key | sign in required |
403 |
Missing sso.manage |
missing permission sso.manage |
404 |
Unknown domain or test result | not found |
409 |
The change would leave no usable break-glass administrator while SSO is required | this change would leave no break-glass administrator with a password and two-factor; single sign-on is required in this workspace |
422 |
A setting is invalid or the connection check failed | invalid sso configuration: turn single sign-on on before requiring it; …: this deployment's public address is "http://localhost:8080": identity providers would send people back to their own computer. Set SP_SSO_PUBLIC_URL (or SP_NOTIFY_PUBLIC_URL) to the https address people use, then configure single sign-on; …: issuer and client ID are required; …: enter the client secret; …: couldn't read the issuer's OpenID configuration: … (including the discovery document’s jwks_uri must be an https URL, and the same for token_endpoint and authorization_endpoint); …: the IdP metadata isn't valid: …; …: couldn't fetch the IdP metadata: …; …: add the IdP metadata (URL or XML); …: unknown role "…"; …: add at least one break-glass administrator with a password and two-factor before requiring single sign-on; …: … isn't an administrator; break-glass accounts must be able to manage people; …: unknown user in the break-glass list; …: the TXT record … wasn't found yet; DNS changes can take a while to appear; …: … is already listed |
429 |
Too many sign-in attempts | too many attempts, try again later |