CAIRLDocs
Integration

Log in with CAIRL (OpenID Connect)

Add CAIRL sign-in to your application through a standard OpenID Connect integration, with a Clerk walkthrough.

What this is

Add CAIRL sign-in 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, consented service.

Use this when your application already runs a login platform (targeting Clerk's custom social connection first; Auth0, Okta, and similar OpenID Connect clients are expected to work but are not promised until tested) and you want "Sign in with CAIRL" without writing protocol code. 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 login 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 credential with Log in with CAIRL enabled on /home/f/{slug}/keys. 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 login platform's secret field).
  2. Register your callback URL on /home/f/{slug}/connect, exactly as your login platform reports it. Matching is strict.

One host per login-enabled context. CAIRL issues a different sub for each partner (pairwise subjects), so all redirect URIs registered for a login-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
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 login 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 login-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.

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.


Not included

Refresh tokens, profile and email scopes, logout, dynamic client registration, sandbox OpenID Connect, and formal certification are not part of this integration. Ask before building on any of them.

On this page