Skip to main content

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

text
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.

javascript
// 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);
php
// 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.

text
GET https://api.yorauth.com/oidc/authorize

Parameters

ParameterRequiredDescription
response_typeYesMust be code
client_idYesYour client's client_id (the oidc_... string)
redirect_uriYesMust exactly match a registered redirect URI
scopeYesSpace-separated scopes. Must include openid.
code_challengeYesBase64url-encoded SHA-256 hash of your code_verifier
code_challenge_methodYesMust be S256
stateRecommendedRandom value to prevent CSRF. Returned unchanged at redirect.
nonceRecommendedRandom value included in the ID token to bind it to this flow.

Example Redirect URL

text
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.

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:

text
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.

bash
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:

ErrorCause
invalid_clientclient_id not found or client is inactive
invalid_redirect_uriredirect_uri is not registered for this client
invalid_request: client_id is requiredMissing client_id parameter
invalid_request: redirect_uri is requiredMissing redirect_uri parameter

Errors Sent as Redirect Parameters

These are returned to your redirect_uri as query parameters:

text
https://yourapp.com/auth/callback
  ?error=invalid_scope
  &error_description=...
  &state=your-state
ErrorCause
unsupported_response_typeresponse_type is not code
invalid_scopeRequested scope not allowed for this client
invalid_request: code_challenge is required (PKCE)Missing code_challenge
invalid_request: code_challenge_method must be S256Unsupported PKCE method
access_deniedUser denied consent on the consent screen

Example Error Handler

javascript
// 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:

text
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.