-
Notifications
You must be signed in to change notification settings - Fork 0
OAuth2
The OAuth2 class provides a generic OAuth 2.0 authorization code flow implementation. It handles authorization URL generation, token exchange, token refresh, JWT parsing, and authenticated API requests via cURL.
The class is provider-agnostic — configure it with any OAuth 2.0 provider (Google, GitHub, Microsoft, etc.) by setting the authorization and token endpoint URLs. It uses the Authorization Code Grant flow with built-in CSRF protection via state tokens.
use Razy\OAuth2;
$oauth = new OAuth2(
'your-client-id', // OAuth client ID
'your-client-secret', // OAuth client secret
'https://example.com/callback' // Redirect URI
);| Method | Return | Description |
|---|---|---|
setAuthorizeUrl(string $url) |
OAuth2 |
Set the authorization endpoint URL |
setTokenUrl(string $url) |
OAuth2 |
Set the token exchange endpoint URL |
setScope(string $scope) |
OAuth2 |
Set requested OAuth scopes (space-separated) |
setState(?string $state = null) |
OAuth2 |
Set CSRF state token (auto-generated if null) |
getState() |
?string |
Get current state token |
addParam(string $key, string $value) |
OAuth2 |
Add extra authorization query parameters |
getAuthorizationUrl() |
string |
Generate the full authorization redirect URL |
getAccessToken(string $code) |
array |
Exchange authorization code for access token |
refreshAccessToken(string $refreshToken) |
array |
Refresh an expired access token |
httpGet(string $url, string $accessToken) |
array |
Make authenticated GET request to an API |
getTokenData() |
array |
Get stored token data from last exchange |
| Method | Return | Description |
|---|---|---|
OAuth2::validateState(string $received, string $expected) |
bool |
Timing-safe CSRF state validation |
OAuth2::parseJWT(string $jwt) |
array |
Decode JWT payload without signature verification |
OAuth2::isJWTExpired(array $claims) |
bool |
Check if JWT claims have expired |
All setter methods return $this for fluent chaining:
use Razy\OAuth2;
$oauth = (new OAuth2($clientId, $clientSecret, $redirectUri))
->setAuthorizeUrl('https://accounts.google.com/o/oauth2/v2/auth')
->setTokenUrl('https://oauth2.googleapis.com/token')
->setScope('openid email profile')
->addParam('access_type', 'offline')
->addParam('prompt', 'consent');Generate the authorization URL and redirect the user. A CSRF state token is automatically generated if not explicitly set.
// Generate authorization URL (state token auto-created)
$authUrl = $oauth->getAuthorizationUrl();
// Store state in session for CSRF verification
$_SESSION['oauth_state'] = $oauth->getState();
// Redirect the user
header('Location: ' . $authUrl);
exit;In your callback handler, validate the state token and exchange the authorization code for an access token:
use Razy\OAuth2;
// Validate CSRF state (timing-safe comparison)
if (!OAuth2::validateState($_GET['state'], $_SESSION['oauth_state'])) {
throw new Exception('Invalid state token — possible CSRF attack');
}
// Exchange code for token
$tokenData = $oauth->getAccessToken($_GET['code']);
// $tokenData contains: access_token, refresh_token, expires_in, etc.
$accessToken = $tokenData['access_token'];
$refreshToken = $tokenData['refresh_token'] ?? null;Use the access token to make authenticated requests:
// Fetch user profile from Google
$profile = $oauth->httpGet(
'https://www.googleapis.com/oauth2/v2/userinfo',
$accessToken
);
echo $profile['email']; // user@example.com
echo $profile['name']; // John DoeWhen an access token expires, use the refresh token to obtain a new one:
$newTokenData = $oauth->refreshAccessToken($refreshToken);
$newAccessToken = $newTokenData['access_token'];Parse and inspect JWT tokens returned by OpenID Connect providers:
use Razy\OAuth2;
// Parse the ID token (no signature verification)
$claims = OAuth2::parseJWT($tokenData['id_token']);
// → ['sub' => '123', 'email' => 'user@example.com', 'exp' => 1700000000, ...]
// Check expiration
if (OAuth2::isJWTExpired($claims)) {
// Token has expired — refresh or re-authenticate
}Note:
parseJWT()decodes the payload without verifying the signature. Use it only for extracting claims from tokens already validated by the provider's token endpoint.
use Razy\OAuth2;
$github = (new OAuth2(
'github-client-id',
'github-client-secret',
'https://myapp.com/auth/github/callback'
))
->setAuthorizeUrl('https://github.com/login/oauth/authorize')
->setTokenUrl('https://github.com/login/oauth/access_token')
->setScope('user:email read:user');
// Redirect to GitHub
$authUrl = $github->getAuthorizationUrl();
$_SESSION['oauth_state'] = $github->getState();
// In callback handler:
$tokens = $github->getAccessToken($_GET['code']);
$user = $github->httpGet('https://api.github.com/user', $tokens['access_token']);
echo $user['login']; // GitHub username