client_secret_basic. Browser-only and mobile-only public clients are unsupported. Keep client secrets, access tokens and refresh tokens on the server; give the browser an opaque, HttpOnly session cookie. Register your application first.
Complete the flow
- Discover the issuer at
https://api.sharedgraph.com/api/auth/.well-known/openid-configuration. Its issuer ishttps://api.sharedgraph.com/api/auth. Use the discovered endpoints and signing keys; discovery and JWKS need no credential. - Create a short-lived, single-use server-side login transaction bound to this browser and application. Generate unpredictable
state,nonceand a PKCE verifier. Store them securely; send only the S256 challenge in the authorization request. - Redirect the browser to the discovered authorization endpoint with
response_type=code, yourclient_id, the exact registeredredirect_uri, space-separated requestedscope,state,nonce,code_challengeandcode_challenge_method=S256. Requestprompt=consent. The provider handles account login and deliberate consent with its own account cookie. - On your callback, consume the login transaction once. Validate state and the authorization response. Exchange the code server-to-server at
/api/auth/oauth2/token, using HTTP Basic client authentication,Content-Type: application/x-www-form-urlencoded,grant_type=authorization_code, the code, the same redirect URI andcode_verifier. Use a maintained OIDC library to validate the ID token, including issuer, audience, signature and nonce. - Reject any granted scope outside the requested set. The OIDC pairwise subject is not the canonical actor identifier. Call
GET /api/sessionwithAuthorization: Bearer <access_token>and bind itsactorId,appId, immutablegrantIdand scopes to your application session. Check thatappIdis your registered client identifier. - Seal token state server-side and establish an application-bound browser session. Revalidate canonical authority before protected operations and again before publishing their results. The starter implements this path.
Token lifetime and rotation
Access tokens live 300 seconds. Refresh tokens live 30 days, subject to earlier revocation or other loss of authority.offline_access requests refresh capability. These lifetimes do not promise continued authority: canonical session admission still applies.
Refresh at the token endpoint with HTTP Basic authentication and form fields grant_type=refresh_token and refresh_token. Refresh scope cannot expand the grant. Rotation is strict, with no reuse interval: atomically replace the old refresh token with the returned token and never spend the parent again. Serialize refresh across every server instance using current durable storage, rather than a process-local lock. If completion is uncertain, retire the session and ask for authorization again. Refreshed authority must preserve actor, application, grant and exact scope set.
The starter’s application session has a separate fixed one-hour admission lifetime and a 15-second durable refresh lease. These are starter choices, not OAuth token lifetimes. Logout retires its durable session and expires its cookie; local logout is distinct from revoking the network grant. Token introspection and revocation also use confidential client Basic authentication.
Origins and headers
The URL itself must use the configured network origin. Do not forward browser
Cookie, Origin or Host into backend transport. See lifecycle and safety for response admission signals and mutation retries.