Integration quickstart
You need an active tenant, a registered OAuth client and the exact issuer assigned to that tenant.
1. Discover the issuer
issuer='https://TENANT.identity.example.com'
curl --fail --silent "$issuer/.well-known/openid-configuration" | jqRead protocol endpoints from discovery instead of assembling them from remembered paths. Reject discovery documents whose issuer is not byte-for-byte equal to the configured issuer.
2. Start authorization
Generate a high-entropy state, nonce and PKCE verifier. Derive its S256 challenge and redirect the browser to the discovered authorization endpoint with:
response_type=code
client_id=YOUR_CLIENT_ID
redirect_uri=YOUR_EXACT_CALLBACK
scope=openid email
state=RANDOM_STATE
nonce=RANDOM_NONCE
code_challenge=BASE64URL_SHA256_VERIFIER
code_challenge_method=S256Add resource=YOUR_API_AUDIENCE when the client needs an access token for an API. Request offline_access explicitly when the client needs a refresh token.
3. Validate the callback
Require the exact callback path, compare state in constant time and reject an unexpected iss. Exchange the one-use code at the discovered token endpoint with the same redirect URI and the original PKCE verifier.
4. Establish application state
For a browser application, keep access and refresh tokens in the server-side BFF session. Send only an HttpOnly application-session cookie to the browser. For an API, bind product state to the exact (iss, sub) after validating the token as described in Resource servers.
Never bind an existing product account by matching email alone.