CAIRLDocs
Integration

Sign in with CAIRL (OpenID Connect)

Add Sign in with CAIRL to your application through a standard OpenID Connect integration, with Clerk and Auth0 walkthroughs.

What this is

Add Sign in with CAIRL through a compatible OpenID Connect integration. CAIRL sends a pseudonymous per-partner identifier and authentication information, not your name, email address, identity documents, age, or verification status. Verification is a separate, authorized service.

Use this when your application already runs an identity platform and you want Sign in with CAIRL without writing protocol code. Walkthroughs below cover Clerk's custom social connection and Auth0's generic OpenID Connect connection; Okta and similar OpenID Connect clients are expected to work but are not promised until tested. If you want verified claims such as age or identity, use the OAuth and OIDC guide instead. The two purposes never mix: a sign-in request cannot carry a verification scope, and a verification request cannot carry openid.


Discovery

Point your identity platform at the discovery document for the environment you integrate against. Every value it advertises is implemented; nothing else is.

EnvironmentDiscovery URL
Productionhttps://cairl.app/.well-known/openid-configuration
Staginghttps://staging.cairl.app/.well-known/openid-configuration

The issuer in each document equals that origin, and every ID token's iss equals the issuer you discovered. Signing keys are published at /.well-known/jwks.json on the same origin (RS256, rotated by publishing the next key before it signs).


Register your application

An Owner or Admin of your CAIRL business context does two things in the dashboard. There is no self-service registration.

  1. Create a sign-in credential on /home/f/{slug}/keys with the Log in with CAIRL option checked (that is the dashboard's label today; it marks the credential as sign-in enabled). A sign-in credential carries openid and nothing else — one key per consent shape, so a sign-in key never carries verification claims. You receive a client_id and a separately generated client_secret. The secret is shown once; store it only on your server (or in your identity platform's secret field).
  2. Register your callback URL on /home/f/{slug}/connect, exactly as your identity platform reports it. Matching is strict.

One host per sign-in-enabled context. CAIRL issues a different sub for each partner (pairwise subjects), so all redirect URIs registered for a sign-in-enabled context must share one host. A second host is refused at registration. Use a separate business context for a second application.


The authorization request

Your platform redirects the User to the authorization endpoint (GET or POST) with:

ParameterValue
response_typecode
client_idYour client ID
redirect_uriA registered callback URL
scopeopenid, alone. Optional: a sign-in key prescribes it
stateRandom value, returned unchanged
code_challengePKCE S256 challenge (required)
code_challenge_methodS256
nonceOptional. When sent, it is echoed byte-for-byte in the ID token
promptOptional. none, login, or consent
max_ageOptional. Seconds since the User last authenticated to CAIRL

The User signs in to CAIRL if needed (or again, when prompt=login or max_age requires it), sees a consent screen naming your application and stating exactly what is shared, and approves or denies. prompt=none never shows a screen: it returns login_required or consent_required to your callback instead.


The token exchange

Exchange the code at the token endpoint with one client authentication method:

  • client_secret_basic: an Authorization: Basic header, or
  • client_secret_post: client_id and client_secret in the form body.

A request that uses both is rejected. The response contains:

{
  "access_token": "…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "openid",
  "id_token": "…"
}

What the ID token contains

Exactly these claims, and never anything else:

ClaimMeaning
issThe issuer you discovered
subThe User's pairwise identifier for your partner. Stable across sign-ins
audYour client_id
iatIssued at
expFive minutes after iat
auth_timeWhen the User authenticated to CAIRL
at_hashHash binding the ID token to the access token
nonceOnly when you sent one
amrOnly when known: pwd, otp, swk, or mfa

The ID token never contains a name, email address, identity document, age, verification status, or any other CAIRL claim.

What userinfo returns

For a sign-in token, GET or POST /api/oauth/userinfo with the bearer access token returns exactly:

{ "sub": "pws_v1_…" }

An ID token presented as a bearer token is rejected.


Errors

WhereCodeMeaning
Authorizationinvalid_scopeopenid was combined with another scope, or the credential is not sign-in enabled
Authorizationinvalid_requestMissing or unsupported PKCE, conflicting prompt, bad max_age
Authorizationlogin_requiredprompt=none and the User is not signed in, or max_age is not met
Authorizationconsent_requiredprompt=none and consent has not been given
Authorizationaccess_deniedThe User denied consent
Tokeninvalid_clientWrong or missing client authentication
Tokeninvalid_requestBoth client authentication methods in one request
Tokeninvalid_grantExpired, replayed, or mismatched code, or the grant was revoked
Tokentemporarily_unavailableSigning is unavailable. Restart the flow

Nothing is ever sent to an unregistered callback URL.


Revocation

A User can remove your application from their CAIRL connected-apps list at any time. Revocation blocks the next authorization, token exchange, and userinfo use for that User. It does not sign the User out of your application's own session, and an already-issued ID token remains valid until its five-minute expiry.


Clerk walkthrough (custom social connection)

Targeting Clerk's custom social connection. In your Clerk dashboard:

  1. Open Configure → SSO connections, choose Add connection → For all users, and pick Custom OIDC provider.

  2. Fill the fields:

    Clerk fieldValue
    NameCAIRL
    Keycairl
    Discovery endpointThe discovery URL for your environment (table above)
    Client IDYour CAIRL client ID
    Client SecretYour CAIRL client secret
    Scopesopenid
  3. Copy the Callback URL Clerk shows for the connection and register it on /home/f/{slug}/connect.

  4. Enable the connection. Clerk's hosted sign-in page now offers Continue with CAIRL (Clerk controls that label).

Expected result: the User is sent to CAIRL, signs in, approves the consent screen, and returns to your application signed in. Clerk stores the sub as the external account identifier. Signing in again returns the same sub. Clerk receives no name or email from CAIRL, so configure Clerk to collect any profile fields your application needs.


Auth0 walkthrough (generic OpenID Connect connection)

Reproduction evidence pending. This walkthrough was written against Auth0's published documentation as of 2026-09-17. Live reproduction on a real Auth0 development tenant is recorded on Linear issue BLD-2996; until that evidence is posted, treat any step Auth0's dashboard presents differently as a documentation gap to report, not as a CAIRL fault.

Before you start: what Auth0 sends

CAIRL requires PKCE (S256) and exactly one client authentication method. Auth0's generic OpenID Connect enterprise connection meets both, provided it is configured as follows. Each fact carries the Auth0 page it was taken from.

RequirementAuth0 behavior
Authorization codeSet the connection Type to Back Channel. Auth0 documents Back Channel as response_type=code, and Front Channel as response_type=id_token with response_mode=form_post. CAIRL's discovery document advertises only code and query, so a Front Channel connection cannot complete. (Connect to OpenID Connect Identity Provider)
PKCE S256The connection's pkce setting defaults to auto, which Auth0 documents as "uses the strongest algorithm available" from the provider's discovery document. CAIRL advertises code_challenge_methods_supported: ["S256"], so auto resolves to S256. Set it to s256 explicitly if you prefer no inference. disabled makes every sign-in fail with invalid_request. (Configure PKCE and Claim Mapping for OIDC Connections)
Client authenticationAuth0's connection token_endpoint_auth_method accepts client_secret_post or private_key_jwt. Use client_secret_post; CAIRL accepts it. client_secret_basic is not an Auth0 connection option and is not needed, and CAIRL does not support private_key_jwt. (Management API: Create a connection)
openid aloneAuth0 requires at least openid in the connection's scopes. CAIRL requires openid and nothing else, so remove profile, email, or anything Auth0 pre-fills. Any extra scope returns invalid_scope. (Connect to OpenID Connect Identity Provider)
Claims sourceAuth0 does not call the provider's userinfo endpoint for this connection type; it reads claims from the ID token. CAIRL's ID token carries only the claims listed above, so the Auth0 user profile receives a sub and no name or email. (Connect to OpenID Connect Identity Provider)

Steps

In your Auth0 dashboard:

  1. Open Authentication → Enterprise → OpenID Connect and choose Create Connection.

  2. Fill the fields:

    Auth0 fieldValue
    Connection namecairl (this becomes part of every Auth0 user_id, so choose it once)
    Issuer URLhttps://cairl.app/.well-known/openid-configuration for production, or the staging discovery URL from the table above
    TypeBack Channel
    Client IDYour CAIRL client ID
    Client SecretYour CAIRL client secret
    Scopesopenid

    Auth0 reads the rest of the configuration (endpoints, JWKS, PKCE method) from the discovery document.

  3. Register the callback URL Auth0 uses for every enterprise connection on /home/f/{slug}/connect:

    https://{your-auth0-domain}/login/callback

    {your-auth0-domain} is the tenant domain shown in your Auth0 settings (for example example.us.auth0.com), or your Auth0 custom domain if you have one. Register the domain your users will actually be sent through: a tenant domain and a custom domain are two hosts, and a sign-in-enabled context may register only one.

  4. On the connection's Applications tab, enable it for the application that should offer Sign in with CAIRL. If you use Auth0's Universal Login, turn on Display connection as a button and set the button text to Sign in with CAIRL.

Expected result: the User is sent to CAIRL, signs in, approves the consent screen, and returns to your application signed in. Auth0 creates the user as oidc|cairl|{sub}, where {sub} is CAIRL's pairwise identifier (Auth0 staff confirm the {strategy}|{connection name}|{provider user id} shape for enterprise connections on the Auth0 Community; verify it on your tenant). Signing in again returns the same sub, so the same Auth0 user. Leave the connection's attribute mapping at its default; there is nothing in the ID token to map besides sub. Auth0 receives no name or email from CAIRL, so collect any profile fields your application needs in your own application or through Auth0 progressive profiling.


Not included

Refresh tokens, profile and email scopes, sign-out (RP-initiated logout), dynamic client registration, private_key_jwt client authentication, sandbox OpenID Connect, and formal certification are not part of this integration. Ask before building on any of them.

On this page