fyennyi / oauth2-vercel
Vercel OAuth 2.0 Client Provider for The PHP League OAuth2-Client.
Fund package maintenance!
Patreon
Open Collective
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/fyennyi/oauth2-vercel
Requires
- php: ^8.0
- firebase/php-jwt: ^7.0
- guzzlehttp/guzzle: ^7.0
- league/oauth2-client: ^2.0
Requires (Dev)
- mockery/mockery: ^1.4
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^9.5 || ^10.0
- squizlabs/php_codesniffer: ^4.0
This package is auto-updated.
Last update: 2026-02-23 22:22:52 UTC
README
This package provides Vercel OAuth 2.0 support for the PHP League's OAuth 2.0 Client.
Features
- Full OAuth 2.0 & OIDC Support: Implements authorization code flow with PKCE.
- Automatic Endpoint Discovery: Configures endpoints from Vercel's OIDC discovery document.
- ID Token Validation: Cryptographically validates ID tokens using JWKS.
- Token Introspection: Check token validity and metadata.
- Token Revocation: Invalidate tokens when needed.
- Easy Integration: Works seamlessly with
league/oauth2-client.
Installation
Install via Composer:
composer require fyennyi/oauth2-vercel
Requirements
- PHP 8.0 or higher
league/oauth2-client^2.0guzzlehttp/guzzle^7.0firebase/php-jwt^7.0
Quick Start
1. Create a Vercel App
Before using this library, you need to create an app in your Vercel account:
- Go to your Vercel Team Settings
- Navigate to Apps and click Create
- Configure your app:
- Name: Your app name
- Client Authentication: Choose your preferred method
- Authorization Callback URL: Add your callback URL (e.g.,
https://yourapp.com/callback) - Permissions: Select scopes (
openid,email,profile,offline_access)
- Generate a Client Secret (if using confidential client authentication)
- Save your Client ID and Client Secret
2. Initialize the Provider
<?php require_once 'vendor/autoload.php'; session_start(); $provider = new \Fyennyi\OAuth2\Client\Provider\Vercel([ 'clientId' => 'your-client-id', 'clientSecret' => 'your-client-secret', 'redirectUri' => 'https://yourapp.com/callback', ]);
3. Authorization Flow
Redirect to Vercel for authorization:
if (!isset($_GET['code'])) { // Generate and store state for CSRF protection $authorizationUrl = $provider->getAuthorizationUrl([ 'scope' => ['openid', 'email', 'profile', 'offline_access'] ]); $_SESSION['oauth2state'] = $provider->getState(); header('Location: ' . $authorizationUrl); exit; }
Handle the callback:
// Verify state to prevent CSRF if (empty($_GET['state']) || (isset($_SESSION['oauth2state']) && $_GET['state'] !== $_SESSION['oauth2state'])) { unset($_SESSION['oauth2state']); exit('Invalid state'); } try { // Exchange code for access token $accessToken = $provider->getAccessToken('authorization_code', [ 'code' => $_GET['code'] ]); // Access token details echo 'Access Token: ' . $accessToken->getToken() . "\n"; echo 'Refresh Token: ' . $accessToken->getRefreshToken() . "\n"; echo 'Expires: ' . date('Y-m-d H:i:s', $accessToken->getExpires()) . "\n"; // Get user information $user = $provider->getResourceOwner($accessToken); echo 'User ID: ' . $user->getId() . "\n"; echo 'Email: ' . $user->getEmail() . "\n"; echo 'Name: ' . $user->getName() . "\n"; echo 'Username: ' . $user->getPreferredUsername() . "\n"; } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) { exit('Error: ' . $e->getMessage()); }
Advanced Usage
Refreshing an Access Token
if ($accessToken->hasExpired()) { $newAccessToken = $provider->getAccessToken('refresh_token', [ 'refresh_token' => $accessToken->getRefreshToken() ]); // Use the new access token }
Token Introspection
Check if a token is active and view its metadata:
$introspection = $provider->introspectToken($accessToken->getToken()); if ($introspection['active']) { echo "Token is active\n"; echo "Subject: " . $introspection['sub'] . "\n"; echo "Expires: " . date('Y-m-d H:i:s', $introspection['exp']) . "\n"; } else { echo "Token is not active\n"; }
Token Revocation
Invalidate a token (logout):
// Revoke the access token $provider->revokeToken($accessToken->getToken()); // Revoke the refresh token (optional) if ($accessToken->getRefreshToken()) { $provider->revokeToken($accessToken->getRefreshToken()); }
Manual Endpoint Configuration
If you need to override specific endpoints:
$provider = new \Fyennyi\OAuth2\Client\Provider\Vercel([ 'clientId' => 'your-client-id', 'clientSecret' => 'your-client-secret', 'redirectUri' => 'https://yourapp.com/callback', 'issuer' => 'https://vercel.com', // Optional: Override specific endpoints 'baseAccessTokenUrl' => 'https://custom-token-endpoint.com', ]);
Available Scopes
Configure which user information your app can access:
| Scope | Description |
|---|---|
openid |
Required for OIDC - issues an ID token |
email |
Access to user's email address |
profile |
Access to user's name, username, and picture |
offline_access |
Issues a refresh token for extended access |
Example with custom scopes:
$authorizationUrl = $provider->getAuthorizationUrl([ 'scope' => ['openid', 'email', 'profile'] ]);
User Data Methods
The VercelUser resource owner provides these methods:
$user = $provider->getResourceOwner($accessToken); $user->getId(); // string - User's unique identifier $user->getEmail(); // string - User's email address $user->isEmailVerified(); // bool - Whether email is verified $user->getName(); // string - User's full name $user->getPreferredUsername(); // string - User's username $user->getPicture(); // string - URL to profile picture $user->toArray(); // array - All user data
Security Best Practices
- Always verify the state parameter to prevent CSRF attacks
- Store tokens securely - Never expose them in client-side code
- Use HTTPS for all OAuth flows in production
- Implement token refresh to maintain sessions without re-authentication
- Revoke tokens when users log out or when compromised
- Validate ID tokens - This library automatically validates signatures and claims
Error Handling
try { $accessToken = $provider->getAccessToken('authorization_code', [ 'code' => $_GET['code'] ]); } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) { // OAuth error from Vercel echo 'OAuth Error: ' . $e->getMessage(); // Get detailed error information $response = $e->getResponseBody(); echo 'Error Code: ' . $response['error']; echo 'Description: ' . $response['error_description']; } catch (\Exception $e) { // Other errors echo 'Error: ' . $e->getMessage(); }
Testing
Run the test suite:
composer test
Run static analysis:
composer phpstan
Check coding standards:
composer phpcs
Run all checks:
composer check
Documentation
- Vercel Sign in with Vercel Documentation
- OAuth 2.0 Client Documentation
- Troubleshooting Guide
- Contributing Guidelines
- Architecture Overview
- Next.js Integration Guide
- Code Comparison: PHP vs Next.js
Contributing
Contributions are welcome and appreciated! Here's how you can contribute:
- Fork the project
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Please make sure to update tests as appropriate and adhere to the existing coding style.
License
This library is licensed under the CSSM Unlimited License v2.0 (CSSM-ULv2). See the LICENSE file for details.
Related Projects
- league/oauth2-client - OAuth 2.0 Client Library
- Vercel Documentation - Official Vercel Documentation