Authorization Code flow
🔑 Auth:
client_id+client_secret(server-side) · 👤 This IS the login — standard OpenID Connect · 📖 Result: tokens on your backend, user profile via UserInfo
The Authorization Code flow is the main way an app logs a user in with Valyd. The browser only
ever carries a one-time code; your backend exchanges it for tokens using your client_secret,
so no token ever touches the front end.
When to use it
- Any app with a backend (web app, SSR site, mobile app with a server) that wants Connect with Valyd.
- You want the user’s profile,
id_verifiedstatus, licenses, or verification proofs after login. - You’re using the drop-in button, the
@valyd/sdk, or your own OIDC library — all of them run this exact flow underneath.
Don’t use it for the Unique Human API — those API-key calls answer “is this a live, unique human?” with no user login involved at all.
How it works
Steps
- Start the flow. Your login route generates a random
state+nonce(and an S256 PKCE pair), stores them server-side, and redirects the browser tohttps://idp.valyd.work/api/auth/oidc/authorizewithclient_id,redirect_uri,response_type=code,scope(must includeopenid),state, andnonce. With the SDK this isvalyd.createAuthorizationRequest({ scope: [...] }). - User authenticates and consents. Valyd shows the consent screen with the requested
scopes; on approval it issues a one-time authorization
code. - Callback. Valyd redirects the browser to your registered
redirect_uriwith?code=…&state=…. Thestateis echoed back unchanged. - CSRF check. Compare the callback
statestrictly against the value you stored. Reject with HTTP 400 on any mismatch, before touching the code. - Exchange the code (server-side).
POST https://idp.valyd.work/api/auth/oidc/tokenwithgrant_type: "authorization_code", your client credentials, thecode, and the sameredirect_uri. The response is a top-level token JSON:access_token,refresh_token,id_token,expires_in(≈ 900),scope,token_type. - Validate the ID token. Verify the RS256 signature against the JWKS at
https://idp.valyd.work/api/auth/oidc/jwks.json, and checkiss,aud(= yourclient_id),exp, and thatnonceequals the value you sent. The SDK’shandleCallback()does steps 4–6 in one call. - Fetch the user.
GET https://idp.valyd.work/api/auth/oidc/userinfowithAuthorization: Bearer <access_token>returnssub(stablevalyd_…id),preferred_username,name,id_verified, and more per the granted scopes. Set your own app session and you’re done.
Security notes
- Codes are single-use, short-lived, and client-bound — exchange immediately; a replay
returns
invalid_grant. - The
statecomparison is your CSRF protection. Never skip it. - The
noncecheck is your replay protection for the ID token. client_secretand tokens live on your backend only — the exchange must never run in the browser.- Access tokens last ~15 minutes; use the refresh flow to renew. Refresh tokens rotate on every use.
- The
redirect_urimust exactly match a registered redirect URI — scheme, host, and path.
Build it
- Drop-in front end: the Sign-in button flow
- Full raw-HTTP walkthrough with SDK + Python/PHP/Java examples: Authentication
- Complete Express example: Node.js quickstart
- Bring your own library via discovery: Use any OIDC library
- What’s inside each token: Tokens
Last updated on