use Lcobucci\JWT\Token;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use OpenIDConnectClient\AccessToken;
-use OpenIDConnectClient\Exception\InvalidTokenException;
use OpenIDConnectClient\OpenIDConnectProvider;
/**
{
// Retrieve access token for current session
$json = session()->get('openid_token');
- $accessToken = new AccessToken(json_decode($json, true));
- // Check if both the access token and the ID token (if present) are unexpired
- $idToken = $accessToken->getIdToken();
- if (!$accessToken->hasExpired() && (!$idToken || !$idToken->isExpired())) {
+ // If no access token was found, reject the refresh
+ if (!$json) {
+ $this->actionLogout();
+ return false;
+ }
+
+ $accessToken = new AccessToken(json_decode($json, true) ?? []);
+
+ // If the token is not expired, refreshing isn't necessary
+ if ($this->isUnexpired($accessToken)) {
return true;
}
- // If no refresh token available, logout
- if ($accessToken->getRefreshToken() === null) {
+ // Try to obtain refreshed access token
+ try {
+ $newAccessToken = $this->refreshAccessToken($accessToken);
+ } catch (\Exception $e) {
+ // Log out if an unknown problem arises
+ $this->actionLogout();
+ throw $e;
+ }
+
+ // If a token was obtained, update the access token, otherwise log out
+ if ($newAccessToken !== null) {
+ session()->put('openid_token', json_encode($newAccessToken));
+ return true;
+ } else {
$this->actionLogout();
return false;
}
+ }
+
+ /**
+ * Check whether an access token or OpenID token isn't expired.
+ */
+ protected function isUnexpired(AccessToken $accessToken): bool
+ {
+ $idToken = $accessToken->getIdToken();
+
+ $accessTokenUnexpired = $accessToken->getExpires() && !$accessToken->hasExpired();
+ $idTokenUnexpired = !$idToken || !$idToken->isExpired();
+
+ return $accessTokenUnexpired && $idTokenUnexpired;
+ }
+
+ /**
+ * Generate an updated access token, through the associated refresh token.
+ * @throws Error
+ */
+ protected function refreshAccessToken(AccessToken $accessToken): ?AccessToken
+ {
+ // If no refresh token available, abort
+ if ($accessToken->getRefreshToken() === null) {
+ return null;
+ }
// ID token or access token is expired, we refresh it using the refresh token
try {
- $provider = $this->getProvider();
-
- $accessToken = $provider->getAccessToken('refresh_token', [
+ return $this->getProvider()->getAccessToken('refresh_token', [
'refresh_token' => $accessToken->getRefreshToken(),
]);
} catch (IdentityProviderException $e) {
- // Refreshing failed, logout
- $this->actionLogout();
- return false;
- } catch (\Exception $e) {
- // Unknown error, logout and throw
- $this->actionLogout();
- throw $e;
+ // Refreshing failed
+ return null;
}
-
- // A valid token was obtained, we update the access token
- session()->put('openid_token', json_encode($accessToken));
-
- return true;
}
/**
*/
protected function getProvider(): OpenIDConnectProvider
{
+ // Setup settings
$settings = $this->config['openid'];
$overrides = $this->config['openid_overrides'] ?? [];
$openIdSettings = $this->loadOpenIdDetails();
$settings = array_replace_recursive($settings, $openIdSettings, $overrides);
- $signer = new \Lcobucci\JWT\Signer\Rsa\Sha256();
- return new OpenIDConnectProvider($settings, ['signer' => $signer]);
+ // Setup services
+ $services = $this->loadOpenIdServices();
+ $overrides = $this->config['openid_services'] ?? [];
+
+ $services = array_replace_recursive($services, $overrides);
+
+ return new OpenIDConnectProvider($settings, $services);
+ }
+
+ /**
+ * Load services utilized by the OpenID Connect provider.
+ */
+ protected function loadOpenIdServices(): array
+ {
+ return [
+ 'signer' => new \Lcobucci\JWT\Signer\Rsa\Sha256(),
+ ];
}
/**
- * Load dynamic service provider options required by the onelogin toolkit.
+ * Load dynamic service provider options required by the OpenID Connect provider.
*/
protected function loadOpenIdDetails(): array
{