|
|
@ -35,7 +35,7 @@ class Client |
|
|
|
|
|
|
|
/** |
|
|
|
* OIDC config fetched from the server or restored from cache |
|
|
|
* @var array<string,mixed> |
|
|
|
* @var ?array<string,mixed> |
|
|
|
*/ |
|
|
|
protected $oidc_config; |
|
|
|
|
|
|
@ -76,7 +76,7 @@ class Client |
|
|
|
* |
|
|
|
* @return ?string |
|
|
|
*/ |
|
|
|
public function getUrl(): string |
|
|
|
public function getUrl(): ?string |
|
|
|
{ |
|
|
|
return $this->oidc_url; |
|
|
|
} |
|
|
@ -84,17 +84,22 @@ class Client |
|
|
|
/** |
|
|
|
* Get the OpenId Connect configuration |
|
|
|
* |
|
|
|
* @return array |
|
|
|
* @return array<string,string|array|bool> |
|
|
|
*/ |
|
|
|
public function getConfiguration(): array |
|
|
|
{ |
|
|
|
if (!isset($this->oidc_config)) |
|
|
|
{ |
|
|
|
$url = $this->oidc_url; |
|
|
|
$this->oidc_config = Authkit2::cache('oidc.config.'.md5($this->oidc_url), function() use ($url) { |
|
|
|
$this->oidc_config = Authkit2::cache('oidc.config.'.md5($this->oidc_url), |
|
|
|
/** |
|
|
|
* @return array<string,string|array|bool> |
|
|
|
*/ |
|
|
|
function() use ($url) { |
|
|
|
$response = (new \GuzzleHttp\Client())->get($url.'/.well-known/openid-configuration'); |
|
|
|
return json_decode($response->getBody(), true); |
|
|
|
}); |
|
|
|
} |
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
return $this->oidc_config; |
|
|
@ -110,10 +115,15 @@ class Client |
|
|
|
if (!isset($this->oidc_jwks)) |
|
|
|
{ |
|
|
|
$client = $this; |
|
|
|
$this->oidc_jwks = Authkit2::cache('oidc.config.'.md5($this->oidc_url).'.jwks', function() use ($client) { |
|
|
|
$this->oidc_jwks = Authkit2::cache('oidc.config.'.md5($this->oidc_url).'.jwks', |
|
|
|
/** |
|
|
|
* @return array<string,array> |
|
|
|
*/ |
|
|
|
function() use ($client) { |
|
|
|
$response = $client->get($client->getConfiguration()['jwks_uri']); |
|
|
|
return json_decode(json_encode($response), true); |
|
|
|
}); |
|
|
|
} |
|
|
|
); |
|
|
|
} |
|
|
|
return $this->oidc_jwks; |
|
|
|
} |
|
|
@ -219,6 +229,15 @@ class Client |
|
|
|
return Token::fromResponse($this, $response); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Generate the URL to redirect to in order to initiate the three-legged |
|
|
|
* oauth flow |
|
|
|
* |
|
|
|
* @param string $redirect_uri url to redirect the user to after authentication |
|
|
|
* @param string[] $scopes scopes to request from the openid provider |
|
|
|
* @param string $state nonce |
|
|
|
* @return string fully formed url |
|
|
|
*/ |
|
|
|
public function createAuthorizationRedirectUrl(string $redirect_uri, array $scopes, string $state): string |
|
|
|
{ |
|
|
|
return $this->getEndpointUrl('authorization').'?'.http_build_query([ |
|
|
@ -230,6 +249,13 @@ class Client |
|
|
|
]); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Generate the URL to redirect to in order to initiate a signout from the |
|
|
|
* OIDC provider |
|
|
|
* |
|
|
|
* @param string $redirect_uri url to redirect the user to after logout |
|
|
|
* @return string fully formed url |
|
|
|
*/ |
|
|
|
public function createLogoutUrl(string $redirect_uri): string |
|
|
|
{ |
|
|
|
return $this->getEndpointUrl('end_session').'?'.http_build_query([ |
|
|
@ -237,11 +263,26 @@ class Client |
|
|
|
]); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Refresh a token using a refresh token |
|
|
|
* |
|
|
|
* @param Token $token expired token that includes a refresh token |
|
|
|
* @return Token newly generated token |
|
|
|
*/ |
|
|
|
public function refreshToken(Token $token): Token |
|
|
|
{ |
|
|
|
return $this->createTokenFromRefreshToken($token->getRefreshToken()); |
|
|
|
$refresh_token = $token->getRefreshToken(); |
|
|
|
if (!isset($refresh_token)) |
|
|
|
throw new \Exception("Cannot refresh token initialized without refresh token"); |
|
|
|
return $this->createTokenFromRefreshToken($refresh_token); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Fetch the available information on the user from the OIDC provider |
|
|
|
* |
|
|
|
* @param Token $token token representing the user |
|
|
|
* @return array<string,mixed> |
|
|
|
*/ |
|
|
|
public function getTokenUserInfo(Token $token): array |
|
|
|
{ |
|
|
|
return json_decode($token->getClient()->get($this->getEndpointUrl('userinfo'))->getBody(), true); |
|
|
@ -249,5 +290,4 @@ class Client |
|
|
|
|
|
|
|
// todo: introspect, etc |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|