Skip to content

Commit 159ecc2

Browse files
feat: support PKCE on Swagger UI
1 parent 92d8f53 commit 159ecc2

File tree

10 files changed

+27
-4
lines changed

10 files changed

+27
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## 2.7.0
44

5+
* Swagger UI: Add `usePkceWithAuthorizationCodeGrant` to Swagger UI initOAuth (#4649)
56
* **BC**: `mapping.paths` in configuration should override bundles configuration (#4465)
67
* GraphQL: Add ability to use different pagination types for the queries of a resource (#4453)
78
* Security: **BC** Fix `ApiProperty` `security` attribute expression being passed a class string for the `object` variable on updates/creates - null is now passed instead if the object is not available (#4184)

src/Core/Bridge/Symfony/Bundle/Action/SwaggerUiAction.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ final class SwaggerUiAction
5656
private $oauthTokenUrl;
5757
private $oauthAuthorizationUrl;
5858
private $oauthScopes;
59+
private $oauthPKCE;
5960
private $formatsProvider;
6061
private $swaggerUiEnabled;
6162
private $reDocEnabled;
@@ -79,9 +80,10 @@ final class SwaggerUiAction
7980
* @param mixed $oauthTokenUrl
8081
* @param mixed $oauthAuthorizationUrl
8182
* @param mixed $oauthScopes
83+
* @param mixed $oauthPKCE
8284
* @param mixed $resourceMetadataFactory
8385
*/
84-
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, $resourceMetadataFactory, NormalizerInterface $normalizer, ?TwigEnvironment $twig, UrlGeneratorInterface $urlGenerator, string $title = '', string $description = '', string $version = '', $formats = [], $oauthEnabled = false, $oauthClientId = '', $oauthClientSecret = '', $oauthType = '', $oauthFlow = '', $oauthTokenUrl = '', $oauthAuthorizationUrl = '', $oauthScopes = [], bool $showWebby = true, bool $swaggerUiEnabled = false, bool $reDocEnabled = false, bool $graphqlEnabled = false, bool $graphiQlEnabled = false, bool $graphQlPlaygroundEnabled = false, array $swaggerVersions = [2, 3], OpenApiSwaggerUiAction $swaggerUiAction = null, $assetPackage = null, array $swaggerUiExtraConfiguration = [])
86+
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, $resourceMetadataFactory, NormalizerInterface $normalizer, ?TwigEnvironment $twig, UrlGeneratorInterface $urlGenerator, string $title = '', string $description = '', string $version = '', $formats = [], $oauthEnabled = false, $oauthClientId = '', $oauthClientSecret = '', $oauthType = '', $oauthFlow = '', $oauthTokenUrl = '', $oauthAuthorizationUrl = '', $oauthScopes = [], bool $oauthPKCE = true, bool $showWebby = true, bool $swaggerUiEnabled = false, bool $reDocEnabled = false, bool $graphqlEnabled = false, bool $graphiQlEnabled = false, bool $graphQlPlaygroundEnabled = false, array $swaggerVersions = [2, 3], OpenApiSwaggerUiAction $swaggerUiAction = null, $assetPackage = null, array $swaggerUiExtraConfiguration = [])
8587
{
8688
$this->resourceNameCollectionFactory = $resourceNameCollectionFactory;
8789
$this->resourceMetadataFactory = $resourceMetadataFactory;
@@ -100,6 +102,7 @@ public function __construct(ResourceNameCollectionFactoryInterface $resourceName
100102
$this->oauthTokenUrl = $oauthTokenUrl;
101103
$this->oauthAuthorizationUrl = $oauthAuthorizationUrl;
102104
$this->oauthScopes = $oauthScopes;
105+
$this->oauthPKCE = $oauthPKCE;
103106
$this->swaggerUiEnabled = $swaggerUiEnabled;
104107
$this->reDocEnabled = $reDocEnabled;
105108
$this->graphqlEnabled = $graphqlEnabled;
@@ -183,6 +186,7 @@ private function getContext(Request $request, Documentation $documentation): arr
183186
'enabled' => $this->oauthEnabled,
184187
'clientId' => $this->oauthClientId,
185188
'clientSecret' => $this->oauthClientSecret,
189+
'pkce' => $this->oauthPKCE,
186190
'type' => $this->oauthType,
187191
'flow' => $this->oauthFlow,
188192
'tokenUrl' => $this->oauthTokenUrl,

src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ private function registerOAuthConfiguration(ContainerBuilder $container, array $
421421
$container->setParameter('api_platform.oauth.enabled', $this->isConfigEnabled($container, $config['oauth']));
422422
$container->setParameter('api_platform.oauth.clientId', $config['oauth']['clientId']);
423423
$container->setParameter('api_platform.oauth.clientSecret', $config['oauth']['clientSecret']);
424+
$container->setParameter('api_platform.oauth.pkce', $config['oauth']['pkce']);
424425
$container->setParameter('api_platform.oauth.type', $config['oauth']['type']);
425426
$container->setParameter('api_platform.oauth.flow', $config['oauth']['flow']);
426427
$container->setParameter('api_platform.oauth.tokenUrl', $config['oauth']['tokenUrl']);

src/Symfony/Bundle/DependencyInjection/Configuration.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,12 @@ private function addOAuthSection(ArrayNodeDefinition $rootNode): void
260260
->addDefaultsIfNotSet()
261261
->children()
262262
->scalarNode('clientId')->defaultValue('')->info('The oauth client id.')->end()
263-
->scalarNode('clientSecret')->defaultValue('')->info('The oauth client secret.')->end()
263+
->scalarNode('clientSecret')
264+
->defaultValue('')
265+
->info('The oauth client secret.')
266+
->setDeprecated(...$this->buildDeprecationArgs('2.7', 'The use of the `oauth.client_secret` has been deprecated in 2.7 for security reasons and will be removed in 3.0. The `oauth.pkce` option implements the OAuth2 PKCE strategy (enabled by default).'))
267+
->end()
268+
->booleanNode('pkce')->defaultTrue()->info('Enable the oauth PKCE.')->end()
264269
->scalarNode('type')->defaultValue('oauth2')->info('The oauth type.')->end()
265270
->scalarNode('flow')->defaultValue('application')->info('The oauth flow grant type.')->end()
266271
->scalarNode('tokenUrl')->defaultValue('')->info('The oauth token url.')->end()

src/Symfony/Bundle/Resources/config/swagger_ui.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
<argument>%api_platform.oauth.tokenUrl%</argument>
3838
<argument>%api_platform.oauth.authorizationUrl%</argument>
3939
<argument>%api_platform.oauth.scopes%</argument>
40+
<argument>%api_platform.oauth.pkce%</argument>
4041
<argument>%api_platform.show_webby%</argument>
4142
<argument>%api_platform.enable_swagger_ui%</argument>
4243
<argument>%api_platform.enable_re_doc%</argument>

src/Symfony/Bundle/Resources/public/init-swagger-ui.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ window.onload = function() {
6363
realm: data.oauth.type,
6464
appName: data.spec.info.title,
6565
scopeSeparator: ' ',
66-
additionalQueryStringParams: {}
66+
additionalQueryStringParams: {},
67+
usePkceWithAuthorizationCodeGrant: data.oauth.pkce,
6768
});
6869
}
6970

src/Symfony/Bundle/SwaggerUi/SwaggerUiAction.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ final class SwaggerUiAction
4040
private $resourceMetadataFactory;
4141
private $oauthClientId;
4242
private $oauthClientSecret;
43+
private $oauthPKCE;
4344

44-
public function __construct($resourceMetadataFactory, ?TwigEnvironment $twig, UrlGeneratorInterface $urlGenerator, NormalizerInterface $normalizer, OpenApiFactoryInterface $openApiFactory, Options $openApiOptions, SwaggerUiContext $swaggerUiContext, array $formats = [], string $oauthClientId = null, string $oauthClientSecret = null)
45+
public function __construct($resourceMetadataFactory, ?TwigEnvironment $twig, UrlGeneratorInterface $urlGenerator, NormalizerInterface $normalizer, OpenApiFactoryInterface $openApiFactory, Options $openApiOptions, SwaggerUiContext $swaggerUiContext, array $formats = [], string $oauthClientId = null, string $oauthClientSecret = null, bool $oauthPKCE = true)
4546
{
4647
$this->resourceMetadataFactory = $resourceMetadataFactory;
4748
$this->twig = $twig;
@@ -53,6 +54,7 @@ public function __construct($resourceMetadataFactory, ?TwigEnvironment $twig, Ur
5354
$this->formats = $formats;
5455
$this->oauthClientId = $oauthClientId;
5556
$this->oauthClientSecret = $oauthClientSecret;
57+
$this->oauthPKCE = $oauthPKCE;
5658

5759
if (null === $this->twig) {
5860
throw new \RuntimeException('The documentation cannot be displayed since the Twig bundle is not installed. Try running "composer require symfony/twig-bundle".');
@@ -89,6 +91,7 @@ public function __invoke(Request $request)
8991
'scopes' => $this->openApiOptions->getOAuthScopes(),
9092
'clientId' => $this->oauthClientId,
9193
'clientSecret' => $this->oauthClientSecret,
94+
'pkce' => $this->oauthPKCE,
9295
],
9396
'extraConfiguration' => $this->swaggerUiContext->getExtraConfiguration(),
9497
];

tests/Symfony/Bundle/Action/SwaggerUiActionTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ public function getInvokeParameters()
102102
'tokenUrl' => '',
103103
'authorizationUrl' => '',
104104
'scopes' => [],
105+
'pkce' => true,
105106
],
106107
'shortName' => 'F',
107108
'operationId' => 'getFCollection',
@@ -137,6 +138,7 @@ public function getInvokeParameters()
137138
'tokenUrl' => '',
138139
'authorizationUrl' => '',
139140
'scopes' => [],
141+
'pkce' => true,
140142
],
141143
'shortName' => 'F',
142144
'operationId' => 'getFItem',
@@ -195,6 +197,7 @@ public function testDoNotRunCurrentRequest(Request $request)
195197
'tokenUrl' => '',
196198
'authorizationUrl' => '',
197199
'scopes' => [],
200+
'pkce' => true,
198201
],
199202
],
200203
])->shouldBeCalled()->willReturn('');

tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ private function runDefaultConfigTests(array $doctrineIntegrationsToLoad = ['orm
148148
'authorizationUrl' => '',
149149
'refreshUrl' => '',
150150
'scopes' => [],
151+
'pkce' => true,
151152
],
152153
'swagger' => [
153154
'versions' => [2, 3],

tests/Symfony/Bundle/SwaggerUi/SwaggerUiActionTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public function getInvokeParameters()
104104
'tokenUrl' => '',
105105
'authorizationUrl' => '',
106106
'scopes' => [],
107+
'pkce' => true,
107108
],
108109
'extraConfiguration' => [],
109110
'shortName' => 'F',
@@ -139,6 +140,7 @@ public function getInvokeParameters()
139140
'tokenUrl' => '',
140141
'authorizationUrl' => '',
141142
'scopes' => [],
143+
'pkce' => true,
142144
],
143145
'extraConfiguration' => [],
144146
'shortName' => 'F',
@@ -192,6 +194,7 @@ public function testDoNotRunCurrentRequest(Request $request)
192194
'tokenUrl' => '',
193195
'authorizationUrl' => '',
194196
'scopes' => [],
197+
'pkce' => true,
195198
],
196199
'extraConfiguration' => [],
197200
],

0 commit comments

Comments
 (0)