Redirect users to a configured OAuth 2.0 authorization server and exchange a one-time authorization code for tokens.
The examples introduce the underlying control before showing a verification and an application-level safeguard.
What You Will Build
Redirect users to a configured OAuth 2.0 authorization server and exchange a one-time authorization code for tokens.
Prerequisites
Use PHP 8.4 or newer, HTTPS for all authentication operations, and an application session or database where required. Example configuration values are placeholders, never production secrets.
Example 1: Basic Operation
Create one-time state, PKCE verifier and S256 code challenge.
<?php
session_start();
$state = bin2hex(random_bytes(32));
$verifier = rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');
$challenge = rtrim(strtr(base64_encode(hash('sha256', $verifier, true)), '+/', '-_'), '=');
$_SESSION['oauth_attempt'] = ['state' => $state, 'verifier' => $verifier];
echo 'PKCE S256 challenge: ' . $challenge;
Example 2: A Different Use Case
Validate the callback state and consume the login attempt once.
<?php
session_start();
$attempt = $_SESSION['oauth_attempt'] ?? [];
$state = $_GET['state'] ?? null;
if (!is_string($state) || !isset($attempt['state']) || !hash_equals($attempt['state'], $state)) {
http_response_code(400); exit('Invalid OAuth state');
}
$code = $_GET['code'] ?? null;
if (!is_string($code) || $code === '') { http_response_code(400); exit; }
$_SESSION['validated_pkce_verifier'] = $attempt['verifier'];
unset($_SESSION['oauth_attempt']);
// Exchange the code at a fixed token endpoint; expire verifier after this attempt.
Practical Example: Checking the Result
Build an authorization request using fixed provider settings, not user-controlled URLs.
<?php
// Run only after the server has validated and consumed the callback state.
// These values must be kept from the same original authorization attempt.
$authorizationCode = $_GET['code'] ?? null;
$verifier = $_SESSION['validated_pkce_verifier'] ?? null;
if (!is_string($authorizationCode) || !is_string($verifier)) { http_response_code(400); exit; }
$tokenEndpoint = 'https://auth.example.test/token'; // Fixed trusted provider setting.
$payload = http_build_query(['grant_type' => 'authorization_code', 'code' => $authorizationCode,
'client_id' => getenv('OAUTH_CLIENT_ID'), 'redirect_uri' => 'https://app.example.test/callback',
'code_verifier' => $verifier], '', '&', PHP_QUERY_RFC3986);
$ch = curl_init($tokenEndpoint);
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded']]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
unset($_SESSION['validated_pkce_verifier']);
if (!is_string($response) || $status !== 200) { throw new RuntimeException('Token exchange failed'); }
$tokens = json_decode($response, true, 512, JSON_THROW_ON_ERROR);
// Validate scope, issuer and token type; store tokens server-side only.
// For login via OpenID Connect, also validate the ID token and nonce.
Important Behavior and Edge Cases
Verify state and PKCE, exact redirect URI, issuer and client identity; never trust arbitrary provider URLs.
Enforce controls on the server, test denial paths and do not assume that a snippet alone implements an entire production workflow.
Comparison with Related Functions
| Approach | Key distinction |
|---|---|
| Implementing OAuth 2.0 Authorization Code Flow | Redirect users to a configured OAuth 2.0 authorization server and exchange a one-time authorization code for tokens. |
| Related technique | OAuth authorizes delegated API access; for user identity use OpenID Connect with ID token validation. |
Common Beginner Mistakes
| Mistake | Correct approach |
|---|---|
| Confusing this operation with a neighboring cryptographic or security mechanism | OAuth authorizes delegated API access; for user identity use OpenID Connect with ID token validation. |
| Ignoring a security prerequisite or failure case | Verify state and PKCE, exact redirect URI, issuer and client identity; never trust arbitrary provider URLs. |
Key Takeaways
- Redirect users to a configured OAuth 2.0 authorization server and exchange a one-time authorization code for tokens.
- Verify state and PKCE, exact redirect URI, issuer and client identity; never trust arbitrary provider URLs.
- OAuth authorizes delegated API access; for user identity use OpenID Connect with ID token validation.
Apply this behavior to a real application only after confirming the required extension, configuration and failure handling on the deployment runtime.