steverhoades / oauth2-openid-connect-server
An OpenID Connect Server that sites on The PHP League's OAuth2 Server
Installs: 4 856 985
Dependents: 9
Suggesters: 0
Security: 0
Stars: 197
Watchers: 19
Forks: 40
Open Issues: 9
Requires
- php: >=7.4
- lcobucci/jwt: 4.1.5|^4.2|^4.3|^5.0
- league/oauth2-server: ^8.4.2|^9.0
Requires (Dev)
- laminas/laminas-diactoros: ^1.3.2 || ^3.3
- phpunit/phpunit: ^5.0|^9.5
README
This implements the OpenID Connect specification on top of The PHP League's OAuth2 Server.
Requirements
- Requires PHP version 7.4 or greater.
- league/oauth2-server 8.4.2 or greater.
Note: league/oauth2-server version may have a higher PHP requirement.
Usage
The following classes will need to be configured and passed to the AuthorizationServer in order to provide OpenID Connect functionality.
- IdentityRepository. This MUST implement the OpenIDConnectServer\Repositories\IdentityProviderInterface and return the identity of the user based on the return value of $accessToken->getUserIdentifier().
- The IdentityRepository MUST return a UserEntity that implements the following interfaces
- OpenIDConnectServer\Entities\ClaimSetInterface
- League\OAuth2\Server\Entities\UserEntityInterface.
- The IdentityRepository MUST return a UserEntity that implements the following interfaces
- ClaimSet. ClaimSet is a way to associate claims to a given scope.
- ClaimExtractor. The ClaimExtractor takes an array of ClaimSets and in addition provides default claims for the OpenID Connect specified scopes of: profile, email, phone and address.
- IdTokenResponse. This class must be passed to the AuthorizationServer during construction and is responsible for adding the id_token to the response.
- ScopeRepository. The getScopeEntityByIdentifier($identifier) method must return a ScopeEntity for the
openid
scope in order to enable support. See examples.
Example Configuration
// Init Repositories $clientRepository = new ClientRepository(); $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); $authCodeRepository = new AuthCodeRepository(); $refreshTokenRepository = new RefreshTokenRepository(); $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // OpenID Connect Response Type $responseType = new IdTokenResponse(new IdentityRepository(), new ClaimExtractor()); // Setup the authorization server $server = new \League\OAuth2\Server\AuthorizationServer( $clientRepository, $accessTokenRepository, $scopeRepository, $privateKey, $publicKey, $responseType ); $grant = new \League\OAuth2\Server\Grant\AuthCodeGrant( $authCodeRepository, $refreshTokenRepository, new \DateInterval('PT10M') // authorization codes will expire after 10 minutes ); $grant->setRefreshTokenTTL(new \DateInterval('P1M')); // refresh tokens will expire after 1 month // Enable the authentication code grant on the server $server->enableGrantType( $grant, new \DateInterval('PT1H') // access tokens will expire after 1 hour ); return $server;
After the server has been configured it should be used as described in the OAuth2 Server documentation.
UserEntity
In order for this library to work properly you will need to add your IdentityProvider to the IdTokenResponse object. This will be used internally to lookup a UserEntity by it's identifier. Additionally your UserEntity must implement the ClaimSetInterface which includes a single method getClaims(). The getClaims() method should return a list of attributes as key/value pairs that can be returned if the proper scope has been defined.
use League\OAuth2\Server\Entities\Traits\EntityTrait; use League\OAuth2\Server\Entities\UserEntityInterface; use OpenIDConnectServer\Entities\ClaimSetInterface; class UserEntity implements UserEntityInterface, ClaimSetInterface { use EntityTrait; protected $attributes; public function getClaims() { return $this->attributes; } }
ClaimSets
A ClaimSet is a scope that defines a list of claims.
// Example of the profile ClaimSet $claimSet = new ClaimSetEntity('profile', [ 'name', 'family_name', 'given_name', 'middle_name', 'nickname', 'preferred_username', 'profile', 'picture', 'website', 'gender', 'birthdate', 'zoneinfo', 'locale', 'updated_at' ]);
As you can see from the above, profile lists a set of claims that can be extracted from our UserEntity if the profile scope is included with the authorization request.
Adding Custom ClaimSets
At some point you will likely want to include your own group of custom claims. To do this you will need to create a ClaimSetEntity, give it a scope (the value you will include in the scope parameter of your OAuth2 request) and the list of claims it supports.
$extractor = new ClaimExtractor(); // Create your custom scope $claimSet = new ClaimSetEntity('company', [ 'company_name', 'company_phone', 'company_address' ]); // Add it to the ClaimExtract (this is what you pass to IdTokenResponse, see configuration above) $extractor->addClaimSet($claimSet);
Now, when you pass the company scope with your request it will attempt to locate those properties from your UserEntity::getClaims().
Install
Via Composer
$ composer require steverhoades/oauth2-openid-connect-server
Testing
To run the unit tests you will need to require league/oauth2-server from the source as this repository utilizes some of their existing test infrastructure.
$ composer require league/oauth2-server --prefer-source
Run PHPUnit from the root directory:
$ vendor/bin/phpunit
License
The MIT License (MIT). Please see License File for more information.