Test, troubleshoot and revoke an SSO connection
A single sign-on connection is an authentication trust root, so downpipes gives you a way to check one before you save it and a way to pull it out the moment you need to. This page is for a self-hoster who has filled in a connection form and wants to confirm it works, diagnose it when a check fails, and understand exactly what happens to live sessions when a connection is disabled or deleted.
There are two ideas to hold separately. The Test connection probe is a read-only check you run while configuring a connection; it never changes anything and never signs anyone in. Revocation is the opposite end of the lifecycle: disabling or deleting a connection takes effect at once and ends the sessions that connection minted. Both sit on the same owner-only management surface.
The Test connection probe
Next to both the OIDC/OAuth2 form and the SAML form is a Test connection button. It runs a read-only connectivity and validity check over the config you have entered, whether or not you have saved it yet, and returns a structured set of pass, warn and fail checks the console renders inline. This exists because a misconfigured connection used to surface only at the first real sign-in, where it could lock everyone out. The probe moves that discovery to before you save.
The probe is deliberately narrow about what it touches. It fetches only the metadata a provider publishes (the OIDC discovery document and the JWKS) and parses the SAML config and certificates you already hold. It never stores anything, never starts a login or redirect, and never follows an authentication flow.
A green test is not a guarantee of a future sign-in
The probe proves the network preconditions of sign-in: that the provider’s metadata is reachable, the issuer matches, and a usable signing key is present. It cannot perform a real credential exchange, because that would require initiating a login, which the read-only rule forbids. So a pass means “nothing is obviously broken”, not “the next person will definitely get in”. The credential itself is first exercised at a real sign-in.
How to read the result
The console shows an overall line plus one line per check. Each check is one of three states, and the overall result is a pass only when no check failed.
| Check state | What it means | Does it block? |
|---|---|---|
| OK | The check verified good. | No |
| Warning | A non-fatal observation worth surfacing, such as a SAML certificate nearing expiry. Sign-in still works. | No, it is advisory |
| Failed | A problem that would break sign-in. | Yes, fix it before saving |
A warning leaves the overall result green: it is an advisory, not a blocker. Only a failed check turns the result red. Because the probe is tolerant, any fault at all, a DNS failure, a timeout, a non-200 response, a missing field, an empty JWKS, an internal-host URL or an unparseable certificate, becomes a failed check rather than an error page. You always get a structured result to read, never a 500.
What the probe checks, by connection type
For an OIDC connection the probe walks the same sequence the live sign-in does. It confirms the issuer is a usable https anchor, fetches the discovery document (or validates the explicit endpoints when all three are pinned), confirms the document’s issuer matches the configured issuer exactly, confirms authorization_endpoint, token_endpoint and jwks_uri are present and https-safe, then fetches the JWKS and confirms at least one usable signing key (an RSA key with n and e, or an EC P-256 key with x and y). A failure short-circuits the dependent step with a clear “skipped” line, so you see the first thing to fix.
For an OAuth2 connection (GitHub-class) there is no discovery document and no JWKS to read, and probing the token endpoint would need a real exchange the read-only rule forbids. The probe therefore validates the https shape of the configured endpoints and says so honestly: a warning records that the credential and exchange are only exercised at the first real sign-in.
For a SAML connection the probe does no network at all (the SSO URL is a browser redirect, never fetched server-side). It confirms an IdP entityID is set, that the SingleSignOnService URL is a valid https endpoint, and that at least one pinned signing certificate parses and is within its validity window. A valid certificate inside the 30-day expiry window is surfaced as a warning so you can plan a rollover.
The probe is SSRF-disciplined
Because the probe fetches operator-supplied URLs, every outbound fetch goes through the same guarded path the live OIDC flow uses: https only, the host screened against IP literals, localhost and Cloudflare Access hosts, redirects refused so a 302 to an internal host cannot be chased, and a hard byte cap. On top of that, a thorough internal-host classifier catches private, loopback, link-local and cloud-metadata addresses. A URL that trips either screen is reported as a failed check and is never fetched. Each fetch is also time-bounded, so a black-holed host surfaces as a clean “timed out” check rather than a hang.
Common failures and their fixes
These are the failures the probe surfaces most often, with the change that clears each one. The detail lines the probe returns are short, actionable and secret-free; they never echo a raw upstream body, header or stack.
| Status | Check | When it happens | Fix |
|---|---|---|---|
| Failed | Discovery document | The document’s issuer does not match the configured issuer. |
Set the issuer to the exact value the provider publishes. For Auth0 that includes the mandatory trailing slash. |
| Failed | Discovery document | The discovery endpoint returns a non-200, or HTML instead of JSON. | Confirm the issuer is the OIDC base with no trailing path and that the provider publishes /.well-known/openid-configuration. |
| Failed | Signing keys (JWKS) | The JWKS is empty, or carries no usable RSA or EC P-256 key. | Confirm the jwks_uri resolves to the provider’s live key set; id_token verification fails without a usable key. |
| Failed | Signing certificate (SAML) | No certificate parses, or none is within its validity window. | Paste the provider’s current X.509 signing certificate PEM, including the BEGIN and END lines. |
| Warning | Signing certificate (SAML) | A valid certificate expires within 30 days. | Plan a rollover; pin the next certificate alongside the current one. |
| Warning | Live exchange (OAuth2) | An OAuth2 provider carries no metadata to probe. | None needed. The endpoint shape is validated; the credential is exercised at first sign-in. |
A failure the probe cannot fully diagnose pre-save is a wrong or missing groups claim or a client-auth method mismatch, because both surface only during a real token exchange. The probe confirms the metadata and keys; the claim and the auth method are provider-side settings you set per the provider’s guidance. The table below cross-links the per-provider traps that most often cause “sign-in works but no roles” or “token endpoint 401”.
Provider gotchas to check first
| Provider | The trap | What to set |
|---|---|---|
The hosted-domain (hd) gate is mandatory and Google sends no groups. |
Set your exact Workspace domain; assign roles in the console, not from a groups claim. | |
| Keycloak | Roles and groups are in the access token only by default. | Turn “Add to ID token” on for the roles mapper and the Group Membership mapper. |
| Okta | The org authorisation server cannot emit a custom groups claim, and a client-auth mismatch returns 401. | Use the custom (default) authorisation server, add the groups claim, and match client_secret_post. |
| Auth0 | Dropping the issuer’s trailing slash causes an issuer mismatch. | Let the preset add the trailing slash; enter the full region in the domain. |
| Microsoft Entra ID | A membership over 200 groups overflows and the group ids do not arrive. | Map authorisation with App Roles in the roles claim instead of group object-ids. |
For the full per-provider must-dos, see Supported providers. For what a successfully emitted groups claim then does, see group-to-role mapping.
Revoking a connection
Connection management is owner-only. The create, delete and enable or disable routes, and the test probe itself, are all gated on the owner-exclusive keys.ceremony capability, and a non-owner attempt records a denied audit event with no outbound fetch. A client secret is write-only: once saved it is never displayed back to the console.
Disabling or deleting takes effect at once. When you disable a connection, or delete it, the engine stamps the current instant on that connection’s revocation axis (idpEpoch). Any session minted through the connection before that instant is rejected on its next request, so the people signed in through that provider are signed out immediately. A disabled connection also drops out of the pre-authentication provider list, so its sign-in button disappears. Deleting additionally removes the connection record and its paired secret.
The session model is revocable along three independent axes, so you can act at the right level of bluntness.
| Axis | What it ends | Triggered by |
|---|---|---|
Per-connection (idpEpoch) |
Every session minted through one connection. | Disabling or deleting that connection. |
Per-subject (sessionEpochSub) |
Every session for one exact person. | Terminating or offboarding that individual. |
| Per-email epoch | Every session keyed to one email address. | An admin terminating a user’s sessions, or that user’s own logout. |
This is why the in-flight case is safe: each session’s signed issue time is captured at the start of the login, before the network round-trips, so a revocation stamped during an in-progress sign-in still exceeds that issue time and kills the resulting session.
Built-in guardrails on the management surface
Beyond the owner-only gate, the IdP management routes are rate-limited, and the SAML path keeps a one-time-use assertion cache (keyed by connection and assertion id) so a captured assertion cannot be replayed within its validity window. These are present in the current code, alongside the single-use RelayState, the InResponseTo bind and a browser-binding cookie that are the primary SAML replay defences.
An SSO outage is not a lockout
A broken or revoked connection is not a way to be locked out of your own backups. Single sign-on is additive: the passkey owner front door and the break-glass owner path stay independent of any connection. So if a provider goes down, or you deliberately pull a connection, the sign-in button for it greys out, but the owner can still reach the console on a passkey and the break-glass token still works. Treat a failed connection as a configuration problem to fix, not an emergency.
Where this fits
Supported providers
The per-provider menu and the must-dos behind each gotcha referenced above.
Connect OIDC or OAuth2
The flow that produces the connection you are testing here.
Connect SAML
The SP-initiated SAML path and its pasted signing certificate.
SSO overview
Why sign-on is optional and additive, and the scope limits to know.
Where the probe results come from
The console renders exactly what the engine’s read-only probe returns: an overall ok flag plus a list of checks, each with a name, a status and a short detail. The engine computes ok as “no check failed” in one place, so the overall line can never disagree with the per-check lines. The probe is exercised directly by the engine’s test suite with a stubbed fetch, so the production path is the path under test. None of this reads a stored secret; the OIDC path needs only the issuer and endpoints, and the SAML path needs only the public certificates and metadata you already hold.
Last updated .