Skip to content

Commit

Permalink
Merge pull request #15 from christiaangoossens/christiaangoossens-pat…
Browse files Browse the repository at this point in the history
…ch-2

Improved OIDC Discovery
  • Loading branch information
jeremy379 committed Apr 26, 2024
2 parents 258f242 + 68486b7 commit 077ca66
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 15 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ Example:
'token_headers' => ['kid' => base64_encode('public-key-added-2023-01-01')]
```

Additionally, you can configure the JWKS url and some settings for discovery in the config file.

## Support

You can fill an issue in the github section dedicated for that. I'll try to maintain this fork.
Expand Down
22 changes: 18 additions & 4 deletions src/IdTokenResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,22 @@ protected function getBuilder(
}

protected function getExtraParams(AccessTokenEntityInterface $accessToken): array {
if (!$this->hasOpenIDScope(...$accessToken->getScopes())) {
return [];
/**
* Include the scope return value, which according to RFC 6749, section 5.1 (and 3.3)
* is also required if the scope doesn't match the requested scope, which it might, and is optional otherwise.
*
* The value of the scope parameter is expressed as a list of space-delimited, case-sensitive strings.
*/
$scopes = $accessToken->getScopes();

$params = [
'scope' => implode(' ', array_map(function ($value) {
return $value->getIdentifier();
}, $scopes)),
];

if (!$this->hasOpenIDScope(...$scopes)) {
return $params;
}

$user = $this->identityRepository->getByIdentifier(
Expand All @@ -98,7 +112,7 @@ protected function getExtraParams(AccessTokenEntityInterface $accessToken): arra
}

$claims = $this->claimExtractor->extract(
$accessToken->getScopes(),
$scopes,
$user->getClaims(),
);

Expand All @@ -111,7 +125,7 @@ protected function getExtraParams(AccessTokenEntityInterface $accessToken): arra
$this->config->signingKey(),
);

return ['id_token' => $token->toString()];
return array_merge($params, ['id_token' => $token->toString()]);
}

private function hasOpenIDScope(ScopeEntityInterface ...$scopes): bool {
Expand Down
91 changes: 80 additions & 11 deletions src/Laravel/DiscoveryController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,28 @@

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Laravel\Passport\Passport;

class DiscoveryController
{
/**
* Compatible with https://openid.net/specs/openid-connect-discovery-1_0.html, chapter 3
*/
public function __invoke(Request $request)
{
$response = [
'issuer' => url('/'),
'authorization_endpoint' => route('passport.authorizations.authorize'),
'token_endpoint' => route('passport.token'),
'response_types_supported' => [
'code',
'token',
'id_token',
'code token',
'code id_token',
'token id_token',
'code token id_token',
'none',
],
'grant_types_supported' => $this->getSupportedGrantTypes(),
'response_types_supported' => $this->getSupportedResponseTypes(),
'subject_types_supported' => [
'public',
],
'id_token_signing_alg_values_supported' => [
'RS256',
],
'scopes_supported' => config('openid.passport.tokens_can'),
'scopes_supported' => $this->getSupportedScopes(),
'token_endpoint_auth_methods_supported' => [
'client_secret_basic',
'client_secret_post',
Expand All @@ -46,4 +42,77 @@ public function __invoke(Request $request)

return response()->json($response, 200, [], JSON_PRETTY_PRINT);
}

/**
* Returns JSON array containing a list of the OAuth 2.0 [RFC6749] scope values that this server supports.
* The server MUST support the openid scope value.
* Servers MAY choose not to advertise some supported scope values even when this parameter is used,
* although those defined in [OpenID.Core] SHOULD be listed, if supported.
*/
private function getSupportedScopes(): array {
$scopes = array_keys(config('openid.passport.tokens_can'));

if (!config('openid.discovery.hide_scopes', false)) {
return $scopes;
}

/**
* Otherwise, only return scopes from the OpenID Core Spec, section 5.4
*/
return array_intersect($scopes, [
'openid',
'profile',
'email',
'address',
'phone',
]);
}

private function getSupportedGrantTypes(): array {
// See PassportServiceProvider for grant types that cannot be disabled
$grants = [
'authorization_code', // Cannot be disabled in Passport
'client_credentials', // Cannot be disabled in Passport
'refresh_token', // Cannot be disabled in Passport
];

if (Passport::$implicitGrantEnabled) {
$grants[] = "implicit";
}

if (Passport::$passwordGrantEnabled) {
$grants[] = "password";
}

return $grants;
}

/**
* Returns JSON array containing a list of the OAuth 2.0 response_type values that this OP supports.
* Dynamic OpenID Providers MUST support the code, id_token, and the id_token token Response Type values.
*/
private function getSupportedResponseTypes(): array {
/**
* These are always possible with Auth Code Grant
*/
$response_types = [
'code',
];

if (Passport::$implicitGrantEnabled) {
/**
* Return all variants, indicating both Auth Code & implicit are allowed
*/
return array_merge($response_types, [
'token',
/**
* TODO: Allow `id_token`, `id_token token`, `code id_token`, `code token`, `code id_token token`
* if we build the Implict Flow path.
* See https://github.com/jeremy379/laravel-openid-connect/issues/6
*/
]);
}

return $response_types;
}
}
11 changes: 11 additions & 0 deletions src/Laravel/config/openid.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@
'jwks_url' => '/oauth/jwks',
],

/**
* Settings for the discovery endpoint
*/
'discovery' => [
/**
* Hide scopes that aren't from the OpenID Core spec from the Discovery,
* default = false (all scopes are listed)
*/
'hide_scopes' => false,
],

/**
* The signer to be used
*/
Expand Down

0 comments on commit 077ca66

Please sign in to comment.