diff --git a/README.md b/README.md index e81579d..9e480ea 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,21 @@ In case you want to change the default scopes, add custom claim sets or change t php artisan vendor:publish --tag=openid ``` +### Discovery and JWKS + +The Laravel Passport integration also provides: + +- a discovery endpoint at `/.well-known/openid-configuration`. +- a JWKS endpoint at `/oauth/jwks`. + +Laravel Passport does not provide a `userinfo` endpoint by default. If you provide one, you can add it to the +discovery document by naming the route `openid.userinfo`. + +```php +Route::get('/oauth/userinfo', 'YourController@userinfo')->middleware('xxx')->name('openid.userinfo'); +``` + + ## Support Found a bug? Got a feature request? [Create an issue](https://github.com/ronvanderheijden/openid-connect/issues). diff --git a/src/Laravel/DiscoveryController.php b/src/Laravel/DiscoveryController.php new file mode 100644 index 0000000..18ac30f --- /dev/null +++ b/src/Laravel/DiscoveryController.php @@ -0,0 +1,46 @@ + url('/'), + 'authorization_endpoint' => route('passport.authorizations.authorize'), + 'token_endpoint' => route('passport.token'), + 'jwks_uri' => route('openid.jwks'), + 'response_types_supported' => [ + 'code', + 'token', + 'id_token', + 'code token', + 'code id_token', + 'token id_token', + 'code token id_token', + 'none', + ], + 'subject_types_supported' => [ + 'public', + ], + 'id_token_signing_alg_values_supported' => [ + 'RS256', + ], + 'scopes_supported' => config('openid.passport.tokens_can'), + 'token_endpoint_auth_methods_supported' => [ + 'client_secret_basic', + 'client_secret_post', + ], + ]; + + if (Route::has('openid.userinfo')) { + $response['userinfo_endpoint'] = route('openid.userinfo'); + } + + return response()->json($response, 200, [], JSON_PRETTY_PRINT); + } +} diff --git a/src/Laravel/JwksController.php b/src/Laravel/JwksController.php new file mode 100644 index 0000000..6e861a9 --- /dev/null +++ b/src/Laravel/JwksController.php @@ -0,0 +1,38 @@ +getPublicKey(); + + // Source: https://www.tuxed.net/fkooman/blog/json_web_key_set.html + $keyInfo = openssl_pkey_get_details(openssl_pkey_get_public($publicKey)); + + $jsonData = [ + 'keys' => [ + [ + 'kty' => 'RSA', + 'n' => rtrim(str_replace(['+', '/'], ['-', '_'], base64_encode($keyInfo['rsa']['n'])), '='), + 'e' => rtrim(str_replace(['+', '/'], ['-', '_'], base64_encode($keyInfo['rsa']['e'])), '='), + ], + ], + ]; + + return response()->json($jsonData, 200, [], JSON_PRETTY_PRINT); + } + + private function getPublicKey(): string { + $publicKey = str_replace('\\n', "\n", app()->make(Config::class)->get('passport.public_key') ?? ''); + + if (!$publicKey) { + $publicKey = 'file://'.Passport::keyPath('oauth-public.key'); + } + + return $publicKey; + } +} diff --git a/src/Laravel/PassportServiceProvider.php b/src/Laravel/PassportServiceProvider.php index f3c3db6..85258d6 100644 --- a/src/Laravel/PassportServiceProvider.php +++ b/src/Laravel/PassportServiceProvider.php @@ -35,22 +35,20 @@ public function boot() __DIR__ . '/config/openid.php' => $this->app->configPath('openid.php'), ], ['openid', 'openid-config']); + $this->loadRoutesFrom(__DIR__.'/routes/web.php'); + Passport\Passport::tokensCan(config('openid.passport.tokens_can')); + + $this->registerClaimExtractor(); } public function makeAuthorizationServer(): AuthorizationServer { $cryptKey = $this->makeCryptKey('private'); - $customClaimSets = config('openid.custom_claim_sets'); - - $claimSets = array_map(function ($claimSet, $name) { - return new ClaimSet($name, $claimSet); - }, $customClaimSets, array_keys($customClaimSets)); - $responseType = new IdTokenResponse( app(config('openid.repositories.identity')), - new ClaimExtractor(...$claimSets), + app(ClaimExtractor::class), Configuration::forSymmetricSigner( app(config('openid.signer')), InMemory::file($cryptKey->getKeyPath()), @@ -67,4 +65,16 @@ public function makeAuthorizationServer(): AuthorizationServer $responseType, ); } + + public function registerClaimExtractor() { + $this->app->singleton(ClaimExtractor::class, function () { + $customClaimSets = config('openid.custom_claim_sets'); + + $claimSets = array_map(function ($claimSet, $name) { + return new ClaimSet($name, $claimSet); + }, $customClaimSets, array_keys($customClaimSets)); + + return new ClaimExtractor(...$claimSets); + }); + } } diff --git a/src/Laravel/routes/web.php b/src/Laravel/routes/web.php new file mode 100644 index 0000000..abce7e3 --- /dev/null +++ b/src/Laravel/routes/web.php @@ -0,0 +1,3 @@ +name('openid.jwks'); +Route::get('/.well-known/openid-configuration', \OpenIDConnect\Laravel\DiscoveryController::class."@discovery")->name('openid.discovery');