Skip to content

Repository files navigation

php-openid-client

Full OpenID client implementation.

Latest Stable VersionTotal DownloadsLicensecodecovBuild Status

Most of the library code is based on the awesome node-openid-client.

The PHP extension gmp could be required.

Implemented specs and features

Supports of the following draft specifications

Installation

Requirements:

  • psr/http-client-implementation implementation
  • psr/http-factory-implementation implementation
  • psr/http-message-implementation implementation
composer require facile-it/php-openid-client

RSA signing algorithms are already included from the JWT Framework package`. If you need other algorithms you should install it manually.

Basic Usage

For a basic usage you shouldn't require any other dependency package.

Every builder have methods to customize instances with other dependencies.

useFacile\OpenIDClient\Client\ClientBuilder;
useFacile\OpenIDClient\Issuer\IssuerBuilder;
useFacile\OpenIDClient\Client\Metadata\ClientMetadata;
useFacile\OpenIDClient\Service\Builder\AuthorizationServiceBuilder;
useFacile\OpenIDClient\Service\Builder\UserInfoServiceBuilder;
usePsr\Http\Message\ServerRequestInterface;
$issuer = (newIssuerBuilder())
->build('https://example.com/.well-known/openid-configuration');
$clientMetadata = ClientMetadata::fromArray([
'client_id' => 'client-id',
'client_secret' => 'my-client-secret',
'token_endpoint_auth_method' => 'client_secret_basic', // the auth method tor the token endpoint'redirect_uris' => [
'https://my-rp.com/callback', ],
]);
$client = (newClientBuilder())
->setIssuer($issuer)
->setClientMetadata($clientMetadata)
->build();
// Authorization$authorizationService = (newAuthorizationServiceBuilder())->build();
$redirectAuthorizationUri = $authorizationService->getAuthorizationUri(
$client,
['login_hint' => 'user_username'] // custom params
);
// you can use this uri to redirect the user// Get access token/** @var ServerRequestInterface::class $serverRequest */$serverRequest = null; // get your server request$callbackParams = $authorizationService->getCallbackParams($serverRequest, $client);
$tokenSet = $authorizationService->callback($client, $callbackParams);
$idToken = $tokenSet->getIdToken(); // Unencrypted id_token$accessToken = $tokenSet->getAccessToken(); // Access token$refreshToken = $tokenSet->getRefreshToken(); // Refresh token$claims = $tokenSet->claims(); // IdToken claims (if id_token is available)// Refresh token$tokenSet = $authorizationService->refresh($client, $tokenSet->getRefreshToken());
// Get user info$userInfoService = (newUserInfoServiceBuilder())->build();
$userInfo = $userInfoService->getUserInfo($client, $tokenSet);

Client registration

See OpenID Connect Dynamic Client Registration 1.0 and RFC7591 OAuth 2.0 Dynamic Client Registration Protocol.

useFacile\OpenIDClient\Service\Builder\RegistrationServiceBuilder;
$registration = (newRegistrationServiceBuilder())->build();
// registration$metadata = $registration->register(
$issuer,
[
'client_name' => 'My client name',
'redirect_uris' => ['https://my-rp.com/callback'],
],
'my-initial-token'
);
// read$metadata = $registration->read($metadata['registration_client_uri'], $metadata['registration_access_token']);
// update$metadata = $registration->update(
$metadata['registration_client_uri'],
$metadata['registration_access_token'],
array_merge($metadata, [
// new metadata
])
);
// delete$registration->delete($metadata['registration_client_uri'], $metadata['registration_access_token']);

Token Introspection

See RFC7662 - OAuth 2.0 Token Introspection.

useFacile\OpenIDClient\Service\Builder\IntrospectionServiceBuilder;
$service = (newIntrospectionServiceBuilder())->build();
$params = $service->introspect($client, $token);

Token Revocation

See RFC7009 - OAuth 2.0 Token Revocation.

useFacile\OpenIDClient\Service\Builder\RevocationServiceBuilder;
$service = (newRevocationServiceBuilder())->build();
$params = $service->revoke($client, $token);

Request Object

You can create a request object authorization request with the Facile\OpenIDClient\RequestObject\RequestObjectFactory class.

This will create a signed (and optionally encrypted) JWT token based on your client metadata.

useFacile\OpenIDClient\RequestObject\RequestObjectFactory;
$factory = newRequestObjectFactory();
$requestObject = $factory->create($client, [/* custom claims to include in the JWT*/]);

Then you can use it to create the AuthRequest:

useFacile\OpenIDClient\Authorization\AuthRequest;
$authRequest = AuthRequest::fromParams([
'client_id' => $client->getMetadata()->getClientId(),
'redirect_uri' => $client->getMetadata()->getRedirectUris()[0],
'request' => $requestObject,
]);

Aggregated and Distributed Claims

The library can handle aggregated and distributed claims:

useFacile\OpenIDClient\Claims\AggregateParser;
useFacile\OpenIDClient\Claims\DistributedParser;
$aggregatedParser = newAggregateParser();
$claims = $aggregatedParser->unpack($client, $userInfo);
$distributedParser = newDistributedParser();
$claims = $distributedParser->fetch($client, $userInfo);

Using middlewares

There are some middlewares and handles available:

SessionCookieMiddleware

This middleware should always be on top of middlewares chain to provide a session for state and nonce parameters.

To use it you should install the dflydev/fig-cookies package:

$ composer require "dflydev/fig-cookies:^2.0"
useFacile\OpenIDClient\Middleware\SessionCookieMiddleware;
usePsr\SimpleCache\CacheInterface;
// Use your PSR-16 simple-cache implementation to persist sessions/** @var CacheInterface $cache */$middleware = newSessionCookieMiddleware($cache/* , $cookieName = "openid", $ttl = 300 */);

The middleware provides a Facile\OpenIDClient\Session\AuthSessionInterface attribute with an Facile\OpenIDClient\Session\AuthSessionInterface stateful instance used to persist session data.

Using another session storage

If you have another session storage, you can handle it and provide a Facile\OpenIDClient\Session\AuthSessionInterface instance in the Facile\OpenIDClient\Session\AuthSessionInterface attribute.

ClientProviderMiddleware

This middleware should always be on top of middlewares chain to provide the client to the other middlewares.

useFacile\OpenIDClient\Middleware\ClientProviderMiddleware;
$client = $container->get('openid.clients.default');
$middleware = newClientProviderMiddleware($client);

AuthRequestProviderMiddleware

This middleware provide the auth request to use with the AuthRedirectHandler.

useFacile\OpenIDClient\Middleware\AuthRequestProviderMiddleware;
useFacile\OpenIDClient\Authorization\AuthRequest;
$authRequest = AuthRequest::fromParams([
'scope' => 'openid',
// other params...
]);
$middleware = newAuthRequestProviderMiddleware($authRequest);

AuthRedirectHandler

This handler will redirect the user to the OpenID authorization page.

useFacile\OpenIDClient\Middleware\AuthRedirectHandler;
useFacile\OpenIDClient\Service\AuthorizationService;
/** @var AuthorizationService $authorizationService */$authorizationService = $container->get(AuthorizationService::class);
$middleware = newAuthRedirectHandler($authorizationService);

CallbackMiddleware

This middleware will handle the callback from the OpenID provider.

It will provide a Facile\OpenIDClient\Token\TokenSetInterface attribute with the final TokenSet object.

useFacile\OpenIDClient\Middleware\CallbackMiddleware;
useFacile\OpenIDClient\Service\AuthorizationService;
/** @var AuthorizationService $authorizationService */$authorizationService = $container->get(AuthorizationService::class);
$middleware = newCallbackMiddleware($authorizationService);

UserInfoMiddleware

This middleware will fetch user data from the userinfo endpoint and will provide an Facile\OpenIDClient\Middleware\UserInfoMiddleware attribute with user infos as array.

useFacile\OpenIDClient\Middleware\UserInfoMiddleware;
useFacile\OpenIDClient\Service\UserInfoService;
/** @var UserInfoService $userInfoService */$userInfoService = $container->get(UserInfoService::class);
$middleware = newUserInfoMiddleware($userInfoService);

Performance improvements for production environment

It's important to use a cache to avoid to fetch issuer configuration and keys on every request.

usePsr\SimpleCache\CacheInterface;
useFacile\OpenIDClient\Issuer\IssuerBuilder;
useFacile\OpenIDClient\Issuer\Metadata\Provider\MetadataProviderBuilder;
useFacile\JoseVerifier\JWK\JwksProviderBuilder;
/** @var CacheInterface $cache */$cache = $container->get(CacheInterface::class); // get your simple-cache implementation$metadataProviderBuilder = (newMetadataProviderBuilder())
->setCache($cache)
->setCacheTtl(86400*30); // Cache metadata for 30 days $jwksProviderBuilder = (newJwksProviderBuilder())
->setCache($cache)
->setCacheTtl(86400); // Cache JWKS for 1 day$issuerBuilder = (newIssuerBuilder())
->setMetadataProviderBuilder($metadataProviderBuilder)
->setJwksProviderBuilder($jwksProviderBuilder);
$issuer = $issuerBuilder->build('https://example.com/.well-known/openid-configuration');

Using Psalm

If you need to use Psalm you can include the plugin in your psalm.xml.

<plugins>
<pluginClass class="Facile\JoseVerifier\Psalm\Plugin" />
</plugins>

About

PHP OpenID Client

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages