Supported identity providers and what each one needs
downpipes ships a preset for each identity provider it knows about. A preset is a vendor template the console pre-fills the moment you pick a provider, so you type only the handful of values that are specific to your tenant (a directory id, an Okta domain, a Keycloak realm) plus your client id and, for a confidential client, the client secret. Everything else, the endpoints, the scopes, the claim names and the known traps, is the default baked into the engine’s preset registry.
This page is the menu for a self-hoster preparing their provider before running the connect flow. It marks which presets are OpenID Connect and which are plain OAuth2, what each one must be told to emit so that group-to-role mapping works, and the one or two provider-specific must-dos the preset assumes you have done at your end. The procedure for entering the values lives on Connect OIDC or OAuth2 and Connect SAML. What the emitted groups then do is covered on group-to-role mapping.
The menu: 8 named providers plus generic OIDC and OAuth2
The registry holds 8 named providers plus a Generic OIDC hatch and a Generic OAuth2 hatch. The named presets are not separate integrations so much as filled-in templates over the same two protocols. Eight of the ten entries speak OpenID Connect, where the engine verifies a signed id_token. Two speak plain OAuth2, where there is no id_token at all: identity comes from the provider’s user API and trust rests on the TLS-protected token exchange.
| Provider | Protocol | id_token verified | Groups reach downpipes via |
|---|---|---|---|
| Microsoft Entra ID | OIDC | Yes (RS256) | App Roles in the roles claim |
| Okta | OIDC | Yes (RS256) | a groups claim on a custom authorisation server |
| Google Workspace | OIDC | Yes (RS256) | nothing in the id_token; sign-in only |
| Keycloak | OIDC | Yes (RS256 or ES256) | a groups claim, once you turn on “Add to ID token” |
| JumpCloud | OIDC | Yes (RS256) | the memberOf attribute |
| Auth0 | OIDC | Yes (RS256) | a namespaced roles claim from a Post-Login Action |
| GitLab | OIDC | Yes (RS256) | the groups_direct id_token claim |
| GitHub | OAuth2 | No id_token to verify | the GitHub API (read:org scope) |
| Generic OIDC | OIDC | Yes (RS256 or ES256) | a groups/roles claim name you supply |
| Generic OAuth2 | OAuth2 | No id_token to verify | the provider’s own API |
OAuth2 has no signed token to check
GitHub and Generic OAuth2 are OAuth2, not OpenID Connect. There is no id_token, so there is no token signature for the engine to verify. The engine reads the person’s profile from the provider’s user API over the TLS-protected exchange and keys identity on an immutable id, never a renameable username. Treat that TLS channel as the trust boundary for those two presets.
What each named preset must be told to emit
Every named provider has a matching step-by-step console setup guide that names the exact field to paste the callback URL into, the numbered clicks at the provider, and how to make the provider emit the claim downpipes reads. The provider-specific must-dos below are the parts most likely to leave you with a working sign-in but no roles, or no sign-in at all.
Microsoft Entra ID
The preset pins the single-tenant v2.0 endpoints, so the issuer ends in /v2.0 and is bound to your directory (tenant) id. Map authorisation with App Roles, which the preset reads from the roles claim, rather than group object-ids. App Roles avoid two real problems at once: the overflow when a person belongs to more than 200 groups, and the GUID-to-name mismatch that group object-ids force on you. Create the app role, then assign a user or a group to it under Enterprise applications so the role name lands in the token.
An Entra membership over 200 groups overflows
When a person belongs to more than 200 groups, Entra stops emitting the group object-ids in the token and instead points at a Graph endpoint this id_token flow does not call. The engine detects the resulting overflow marker and fails closed: sign-in is refused outright with an explicit reason, rather than letting the person in with a group-keyed role silently missing. App Roles sidestep the limit entirely, which is why the preset and the setup guide both steer you to them.
Okta
The Okta preset uses a custom authorisation server, with the path /oauth2/{authServerId} defaulting to default. This matters because Okta’s org authorisation server cannot emit a filtered or custom claim, which is the single most common Okta sign-on support ticket. On the custom server, add a groups claim (Value type Groups, filter “Matches regex .*”) so group display names reach the id_token. Two further traps: a claim returns at most about 100 groups before the token request fails, so use a tighter filter on a large directory; and register the same client-authentication method at Okta that the connection uses. The engine defaults to client_secret_post, while Okta’s own default for a web app is client_secret_basic, and a mismatch returns a token-endpoint 401.
Google Workspace
Two things define the Google preset. First, the preset sets the hosted-domain (hd) parameter from your Workspace domain. It is sent on the outbound authorisation request as a login hint that steers Google’s account chooser towards your domain, and it is also enforced on the returned token: after the id_token’s signature and audience are verified, the engine refuses any sign-in whose Google-signed hd claim (or, failing that, whose verified email domain) is not your configured domain. So the hint narrows the prompt and the check closes the gate, and an account outside your Workspace cannot complete sign-in even if it ignores the hint. Second, Google does not put group membership in the id_token. The preset therefore signs people in with no groups, and you assign each person’s role on the Roles and access tab. Workspace group sync through the Cloud Identity API is a possible later add-on, not part of sign-in today.
Keycloak
Keycloak is the preset most likely to give you sign-in but no roles, because by default Keycloak puts roles and groups in the access token only, and the engine verifies the id_token. The fix is to turn “Add to ID token” on for both the realm-roles (or client-roles) mapper and the Group Membership mapper. Add a Group Membership protocol mapper writing a groups claim, which the preset reads, and keep “Full group path” off so the claim carries plain names rather than /parent/child paths. The preset uses the modern /realms/{realm} discovery path, so do not include the legacy /auth segment in your host.
JumpCloud
JumpCloud uses one shared issuer for every tenant, so the issuer does not identify your organisation. Trust instead rests on the client id (the audience check) and the connection id, which is folded into every subject the engine mints. Emit groups by enabling the group attribute on the application’s SSO settings and setting the Groups Attribute Name to memberOf, which is an attribute mapping rather than a scope. The preset handles the awkward shape JumpCloud produces here: a one-group member’s memberOf is a bare string, while a multi-group member’s is an array, and the engine coerces the bare string to a one-element array so both behave the same. The preset is the US region (oauth.id.jumpcloud.com); EU or IN tenants have a different issuer host and should use the Generic OIDC preset with the regional discovery URL.
Auth0
The Auth0 issuer has a mandatory trailing slash (https://<domain>/), which the preset adds for you. Dropping it is the classic Auth0 “issuer mismatch” failure, so leave the preset to handle it. Enter the full tenant host including the region (for example your-tenant.us.auth0.com) or your custom domain, or discovery will not resolve. Roles are not emitted by default. To map them, set the roles-claim namespace (a URL ending in /) and add a Post-Login Action that writes namespace + "roles" from event.authorization.roles; because the namespace already ends in /, the claim key reads as <namespace>roles (for example https://app.yourcompany.com/roles), and the engine reads that same namespaced claim. Leave the namespace blank for sign-in only.
GitLab
GitLab works for gitlab.com (the default host) and for self-managed or Dedicated instances when you set your own host. Group mapping reads the groups_direct id_token claim, which carries direct memberships only. The richer groups claim (direct plus inherited) and the owner, maintainer and developer claims are emitted only at the /userinfo endpoint, which this id_token flow does not read, so groups_direct is the correct claim here. It needs GitLab 16.11 or newer; older self-managed instances do not emit it.
GitHub
GitHub is the OAuth2 preset for code-hosting teams. There is no id_token, so identity comes from the GitHub user API and authorisation keys on your immutable numeric GitHub user id, never the renameable login. The preset requests the read:org and user:email scopes; read:org is what lets downpipes read your team and organisation membership for group-to-role mapping. If your organisation has OAuth App access restrictions on, which is the default for newer organisations, an owner must approve the downpipes OAuth app before membership is returned. Register a classic OAuth App, not a GitHub App.
When to reach for a generic hatch
The two generic presets exist for any provider without a named template.
Reach for Generic OIDC for any spec-compliant provider that publishes a /.well-known/openid-configuration document. The same preset absorbs Auth0, PingOne, OneLogin, Authentik, Zitadel, Curity and similar, and it is also the route for a regional JumpCloud tenant. A generic OIDC connection needs the issuer URL (the base that serves the discovery document over https, matching the iss in its tokens exactly), your client id and your client secret. If your provider can put a groups or roles array in the id_token, name that claim; leave it blank for sign-in only. Because the engine verifies the id_token, make sure the claim is in the ID token, not only in the access token or at /userinfo.
Reach for Generic OAuth2 for any OAuth2 provider that has no id_token, such as Discord, Bitbucket or a plain OAuth GitLab app. A generic OAuth2 connection needs four endpoints (authorisation URL, token URL, API base URL, user-info URL) plus the field in the profile response that holds the person’s immutable id. As with GitHub, use the immutable numeric or opaque id, never a username.
Secret modes: what works at sign-in
The console offers two ways to hold a connection’s credential, and both work end to end at sign-in. A confidential client stores its secret in a write-only engine key (the do-plaintext floor), exactly like a console-set destination secret, and the value is never read back to the console. A public client (the “Public client (PKCE, no secret)” tick box) holds no secret at all and proves itself with PKCE.
The engine’s connection type names two further modes, secrets-store (referencing a Cloudflare Secrets Store binding by name) and private-key-jwt, but the console does not offer them and neither can be saved in this build: the connection validator rejects both at config time, before anything is written to storage, with a clear reason (secrets-store resolution and private_key_jwt client authentication are not yet supported). This is a deliberate fail-closed choice so a connection can never be left in a state that only breaks at first login. Use a confidential do-plaintext client or a PKCE public client until those modes are wired.
| Secret mode | Saves | Works at first login | Holds at rest |
|---|---|---|---|
| PKCE public client | Yes | Yes | nothing (PKCE only) |
| Confidential (do-plaintext) | Yes | Yes | a write-only engine key, never shown back |
| secrets-store | No, rejected at save | n/a | nothing, rejected before persistence |
| private-key-jwt | No, rejected at save | n/a | nothing, rejected before persistence |
The default operational posture can decrypt
Holding a connection secret is unrelated to backup data: the vendor holds nothing of either kind. Separately, on the data side the engine holds a decryption-capable operational private key only where you have added one, under the two-recipient posture. See the no-custody trust model for what that means and how to switch to a break-glass-only posture.
Where this fits
SSO overview
Why single sign-on is optional and additive, and the v1 scope limits to know before you connect any provider.
Connect OIDC or OAuth2
The step-by-step flow for entering a preset’s values and adding a connection.
Connect SAML
The SAML 2.0 path, which is sign-only and SP-initiated, with a pasted signing certificate as the trust anchor.
Group-to-role mapping
What the emitted groups do once they reach downpipes, and how a group becomes a role.
After you pick a provider and enter its values, run the pre-save check and learn how to read it on Test and troubleshoot SSO.
A note on SAML, which has no preset
SAML 2.0 is configured through a generic guide rather than a per-vendor preset, because the value you register at your IdP is the ACS (Assertion Consumer Service) URL and the SP entity id, not a client id and secret. Trust comes from an IdP signing certificate you paste in. downpipes is SP-initiated only and verifies the assertion signature against that certificate; IdP-initiated sign-in cannot be enabled, a transient NameID is not accepted (use persistent, emailAddress, or unspecified), and signed assertions are required. The full procedure is on Connect SAML.
Last updated .