Authorization Flow
YorAuth implements the OAuth 2.0 Authorization Code flow with PKCE (Proof Key for Code Exchange). PKCE is mandatory — all authorization requests must include a code_challenge using the S256 method. This prevents authorization code interception attacks and is required for both public and confidential clients.
Flow Overview
Your App User Browser YorAuth
│ │ │
│ 1. Generate PKCE pair │ │
│ code_verifier (random) │ │
│ code_challenge = base64url(sha256(code_verifier)) │
│ │ │
│ 2. Redirect to /oidc/authorize │
│─────────────────────────────────────────────────────>│
│ │ 3. Show login screen │
│ │<────────────────────────│
│ │ 4. User enters │
│ │ credentials │
│ │────────────────────────>│
│ │ (MFA if enabled) │
│ │ 5. Show consent │
│ │<────────────────────────│
│ │ 6. User approves │
│ │────────────────────────>│
│ 7. Redirect to redirect_uri?code=...&state=... │
│<─────────────────────────────────────────────────────│
│ │ │
│ 8. POST /oidc/token (with code + code_verifier) │
│─────────────────────────────────────────────────────>│
│ 9. Returns id_token (+ refresh_token) │
│<─────────────────────────────────────────────────────│
Step 1: Generate a PKCE Pair
Before redirecting the user, your application generates a code_verifier and derives the code_challenge from it.
// Generate a cryptographically random code_verifier (43–128 characters)
function generateCodeVerifier() {
const array = new Uint8Array(64);
crypto.getRandomValues(array);
return btoa(String.fromCharCode(...array))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
// Derive the code_challenge using SHA-256 (S256 method)
async function generateCodeChallenge(verifier) {
const encoded = new TextEncoder().encode(verifier);
const digest = await crypto.subtle.digest('SHA-256', encoded);
return btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
const codeVerifier = generateCodeVerifier();
const codeChallenge = await generateCodeChallenge(codeVerifier);
// Store code_verifier securely for Step 3 (sessionStorage or server-side session)
sessionStorage.setItem('pkce_code_verifier', codeVerifier);
// Generate code_verifier
$codeVerifier = rtrim(strtr(base64_encode(random_bytes(64)), '+/', '-_'), '=');
// Derive code_challenge (S256)
$codeChallenge = rtrim(
strtr(base64_encode(hash('sha256', $codeVerifier, true)), '+/', '-_'),
'='
);
// Store code_verifier in session for later verification
session(['pkce_code_verifier' => $codeVerifier]);
Step 2: Redirect to the Authorization Endpoint
The authorization endpoint is the web-based hosted login flow. Redirect the user's browser here — do not call this as an API.
GET https://api.yorauth.com/oidc/authorize
Parameters
| Parameter | Required | Description |
|---|---|---|
response_type | Yes | Must be code |
client_id | Yes | Your client's client_id (the oidc_... string) |
redirect_uri | Yes | Must exactly match a registered redirect URI |
scope | Yes | Space-separated scopes. Must include openid. |
code_challenge | Yes | Base64url-encoded SHA-256 hash of your code_verifier |
code_challenge_method | Yes | Must be S256 |
state | Recommended | Random value to prevent CSRF. Returned unchanged at redirect. |
nonce | Recommended | Random value included in the ID token to bind it to this flow. |
Example Redirect URL
https://api.yorauth.com/oidc/authorize
?response_type=code
&client_id=oidc_AbCdEfGhIjKlMnOpQrStUvWxYz012345
&redirect_uri=https%3A%2F%2Fyourapp.com%2Fauth%2Fcallback
&scope=openid%20profile%20email
&state=xK9mNpQrStUv3WxYz012
&nonce=abc123def456
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
The state parameter is strongly recommended. YorAuth returns it unchanged in the redirect, and your application should verify it matches the value you sent to prevent CSRF attacks.
Step 3: User Authentication
After validating the parameters, YorAuth stores the flow context in a server-side session and presents the hosted login screen to the user. The session times out after 15 minutes of inactivity.
The hosted flow handles:
- Email/password login
- Registration (new user accounts)
- MFA verification (TOTP or backup codes) — presented automatically if the user has MFA enabled
- Password reset (email link-based)
- Social login (redirects to configured OAuth providers via YorAuth Gate)
- Passkey authentication (WebAuthn)
Your application is not involved in this step. YorAuth manages the entire authentication UX using the branding configuration of the OIDC client.
Step 4: Consent
After successful authentication, YorAuth checks whether the user has previously granted the requested scopes to this client. If a valid consent grant exists, the consent screen is skipped and the user is redirected immediately. See Consent Management for details.
If consent is required, YorAuth presents a consent screen listing the permissions requested. The user can approve or deny.
Step 5: Authorization Code Redirect
On success, YorAuth redirects the user's browser to your redirect_uri with the authorization code:
https://yourapp.com/auth/callback
?code=64-character-random-code
&state=xK9mNpQrStUv3WxYz012
The code is a single-use value. Authorization codes expire after 10 minutes. The code itself is a 64-character random string — YorAuth stores only its SHA-256 hash, so the plaintext value is never persisted.
Always verify that the state parameter in the redirect matches what you sent in Step 2. Mismatches indicate a potential CSRF attack.
Step 6: Exchange the Code
Exchange the authorization code at the token endpoint. See Token Endpoint for the full request format.
curl -X POST https://api.yorauth.com/oidc/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=the-code-from-redirect" \
-d "redirect_uri=https://yourapp.com/auth/callback" \
-d "client_id=oidc_AbCdEfGhIjKlMnOpQrStUvWxYz012345" \
-d "client_secret=your-client-secret" \
-d "code_verifier=your-original-code-verifier"
Error Handling
If the authorization request fails, YorAuth either shows an error page or redirects to your redirect_uri with error parameters, depending on the nature of the error.
Errors That Show an Error Page (No Redirect)
These errors occur before redirect_uri can be trusted, so YorAuth does not redirect:
| Error | Cause |
|---|---|
invalid_client | client_id not found or client is inactive |
invalid_redirect_uri | redirect_uri is not registered for this client |
invalid_request: client_id is required | Missing client_id parameter |
invalid_request: redirect_uri is required | Missing redirect_uri parameter |
Errors Sent as Redirect Parameters
These are returned to your redirect_uri as query parameters:
https://yourapp.com/auth/callback
?error=invalid_scope
&error_description=...
&state=your-state
| Error | Cause |
|---|---|
unsupported_response_type | response_type is not code |
invalid_scope | Requested scope not allowed for this client |
invalid_request: code_challenge is required (PKCE) | Missing code_challenge |
invalid_request: code_challenge_method must be S256 | Unsupported PKCE method |
access_denied | User denied consent on the consent screen |
Example Error Handler
// In your callback route handler
const params = new URLSearchParams(window.location.search);
if (params.has('error')) {
console.error('Authorization failed:', params.get('error'));
console.error('Description:', params.get('error_description'));
// Redirect user to an error page
return;
}
const code = params.get('code');
const returnedState = params.get('state');
// Verify state matches stored value
const storedState = sessionStorage.getItem('oauth_state');
if (returnedState !== storedState) {
throw new Error('State mismatch — possible CSRF attack');
}
// Proceed to token exchange
PKCE Verification Details
At the token endpoint, YorAuth verifies the code_verifier against the stored code_challenge using this computation:
expected = base64url(sha256(code_verifier))
stored = code_challenge from authorization request
if not constant_time_equal(expected, stored):
reject with invalid_grant
This verification is mandatory. Authorization codes that were created without a code_challenge are rejected at the token endpoint regardless of what code_verifier is provided.