digitalcz / openid-connect
PHP implementation of OpenID Connect using symfony/contracts
v1.1.0
2025-09-22 14:04 UTC
Requires
- php: ^8.4
- symfony/cache-contracts: ^3.6
- symfony/http-client-contracts: ^3.6
- web-token/jwt-library: ^4.0
Requires (Dev)
- digitalcz/coding-standard: ^0.4.0
- ergebnis/composer-normalize: ^2.47
- phpstan/phpstan: ^2.1
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^12.2
- symfony/cache: ^7.3
- symfony/http-client: ^7.3
- symfony/var-dumper: ^7.3
- 1.x-dev
- v1.1.0
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- v1.0.0-beta1
- v1.0.0-alpha2
- v1.0.0-alpha1
- 0.x-dev
- v0.4.0
- v0.3.1
- v0.3.0
- v0.2.1
- v0.2.0
- v0.1.0
- dev-claude/fix-openid-connect-config-hgnvs
- dev-claude/fix-openid-connect-config-u4Hjp
- dev-claude/select-issue-UmdbM
- dev-dependabot/github_actions/codecov/codecov-action-6
- dev-copilot/add-back-channel-logout-support
This package is auto-updated.
Last update: 2026-05-27 09:55:39 UTC
README
PHP implementation of OpenID Connect using symfony/contracts
Install
Via Composer
$ composer require digitalcz/openid-connect
Usage
Initialization
Using the OIDC discovery endpoint
use DigitalCz\OpenIDConnect\OidcFactory; use Symfony\Component\HttpClient\HttpClient; $httpClient = HttpClient::create(); $oidc = OidcFactory::create( httpClient: $httpClient, issuer: 'https://auth.example.com', clientId: 'my-client-id', clientSecret: 'my-client-secret', redirectUri: 'https://myapp.example.com/callback', );
Using manual issuer configuration
use DigitalCz\OpenIDConnect\OidcFactory; use DigitalCz\OpenIDConnect\Config\IssuerMetadata; use Symfony\Component\HttpClient\HttpClient; $httpClient = HttpClient::create(); $issuerMetadata = new IssuerMetadata([ 'authorization_endpoint' => 'https://auth.example.com/authorize', 'token_endpoint' => 'https://auth.example.com/token', 'jwks_uri' => 'https://auth.example.com/.well-known/jwks.json', 'issuer' => 'https://auth.example.com', ]); $oidc = OidcFactory::create( httpClient: $httpClient, issuer: $issuerMetadata, clientId: 'my-client-id', clientSecret: 'my-client-secret', redirectUri: 'https://myapp.example.com/callback', );
Configuration Options
The OidcFactory::create() method accepts the following configuration options:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
httpClient |
HttpClientInterface |
✓ | - | HTTP client for making requests |
issuer |
string|array|IssuerMetadata |
✓ | - | Issuer URL for discovery, metadata array, or IssuerMetadata instance |
clientId |
string |
✓ | - | OAuth2/OIDC client identifier |
clientSecret |
string|null |
- | null |
OAuth2/OIDC client secret (required for some authentication methods) |
redirectUri |
string|null |
- | null |
Redirect URI for authorization code flow |
defaultScopes |
string|array |
- | ['openid', 'profile', 'email'] |
Default scopes to request (space-separated string or array) |
authenticationMethod |
string|AuthenticationMethod |
- | client_secret_post |
Client authentication method for token endpoint |
pkceMethod |
string|PkceMethod |
- | S256 |
PKCE method for authorization code flow (S256, plain, or none) |
cache |
CacheInterface|null |
- | null |
Optional cache for storing discovery metadata and JWKS |
clock |
ClockInterface |
- | SimpleClock |
Clock implementation for time-based operations |
cacheSecret |
string |
- | 'default-oidc-cache-secret' |
Secret used for HMAC-based cache key generation |
privateKey |
string|null |
- | null |
PEM-encoded private key for private_key_jwt authentication |
privateKeyJwk |
JWK|null |
- | null |
JWK private key for private_key_jwt authentication (alternative to privateKey) |
tokenEndpointAuthSigningAlg |
string|null |
- | null |
Signature algorithm for client assertion JWT (e.g., 'HS256', 'RS256') |
clientAssertionAudience |
string|null |
- | null |
Audience claim for client assertion JWT. Special values: '{issuer}', '{token_endpoint}', or custom URL |
Authentication Methods
client_secret_post- Send client credentials in POST bodyclient_secret_basic- Send client credentials in Authorization headerclient_secret_jwt- Use JWT signed with client secretprivate_key_jwt- Use JWT signed with private keynone- No client authentication (public clients)
Authorization Code flow
Step 1 - Redirect the user to authorization endpoint
$authorizationCode = $oidc->authorizationCode(); // createAuthorizationUrl() auto-generates cryptographically random state, nonce, and PKCE // code_verifier. Retrieve them from the result and persist in session before redirecting. $result = $authorizationCode->createAuthorizationUrl(); // IMPORTANT: Store security parameters in session before redirecting. // - state: must be verified on callback to prevent CSRF attacks // - nonce: must be passed to fetchTokens() to validate the ID token // - codeVerifier: must be passed to fetchTokens() when PKCE is enabled (default) session_start(); $_SESSION['oauth_state'] = $result->state(); $_SESSION['oauth_nonce'] = $result->nonce(); $_SESSION['oauth_code_verifier'] = $result->codeVerifier(); // Redirect user to $result->url()
Step 2 - Handle the callback and exchange code for tokens
session_start(); // IMPORTANT: Always validate the state parameter before proceeding. // A missing or mismatched state indicates a potential CSRF attack. if ( empty($_GET['state']) || !isset($_SESSION['oauth_state']) || !hash_equals($_SESSION['oauth_state'], $_GET['state']) ) { throw new RuntimeException('Invalid state parameter - possible CSRF attack.'); } $code = $_GET['code']; $tokens = $authorizationCode->fetchTokens( code: $code, nonce: $_SESSION['oauth_nonce'], codeVerifier: $_SESSION['oauth_code_verifier'], ); // Clear one-time security parameters from session unset($_SESSION['oauth_state'], $_SESSION['oauth_nonce'], $_SESSION['oauth_code_verifier']); echo "Access Token: " . $tokens->accessToken() . PHP_EOL; echo "ID Token: " . $tokens->idToken() . PHP_EOL; echo "Refresh Token: " . $tokens->refreshToken() . PHP_EOL;
Client Credentials flow
$clientCredentials = $oidc->clientCredentials(); $tokens = $clientCredentials->fetchTokens(); echo "Access Token: " . $tokens->accessToken() . PHP_EOL;
Resource Server (Token Validation)
use DigitalCz\OpenIDConnect\ResourceServer\JwtAccessToken; use DigitalCz\OpenIDConnect\ResourceServer\OpaqueAccessToken; use DigitalCz\OpenIDConnect\Util\JWT; $resourceServer = $oidc->resourceServer(); $accessToken = new JwtAccessToken($jwt); $validatedToken = $resourceServer->introspect($accessToken); echo "Token is valid for subject: " . $validatedToken->sub() . PHP_EOL; echo "Token expires at: " . date('Y-m-d H:i:s', $validatedToken->exp()) . PHP_EOL;
See examples for more complete examples
Testing
$ composer csfix # fix codestyle $ composer checks # run all checks # or separately $ composer tests # run phpunit $ composer phpstan # run phpstan $ composer cs # run codesniffer
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security related issues, please email devs@digital.cz instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.