From 84e123f61a85e1606b7672d68c4a4e87568d7615 Mon Sep 17 00:00:00 2001 From: Jakov Knezovic Date: Thu, 26 Feb 2026 10:24:03 +0100 Subject: [PATCH 1/6] NGSTACK-1017 extend gesdinet model with class property --- config/doctrine/RefreshToken.orm.xml | 18 ++++++++++++++++ src/Entity/RefreshToken.php | 9 ++++++++ src/Model/UserAwareRefreshToken.php | 31 ++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 config/doctrine/RefreshToken.orm.xml create mode 100644 src/Entity/RefreshToken.php create mode 100644 src/Model/UserAwareRefreshToken.php diff --git a/config/doctrine/RefreshToken.orm.xml b/config/doctrine/RefreshToken.orm.xml new file mode 100644 index 0000000..439fe2b --- /dev/null +++ b/config/doctrine/RefreshToken.orm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/src/Entity/RefreshToken.php b/src/Entity/RefreshToken.php new file mode 100644 index 0000000..b0bddae --- /dev/null +++ b/src/Entity/RefreshToken.php @@ -0,0 +1,9 @@ +setClass($user::class); + } + + public function getClass(): string + { + return $this->class; + } + + public function setClass(string $class): static + { + $this->class = $class; + + return $this; + } +} From 0bc10a2ccdd7adb65d4f66bbee11c3ba6f491c1d Mon Sep 17 00:00:00 2001 From: Jakov Knezovic Date: Thu, 26 Feb 2026 10:25:15 +0100 Subject: [PATCH 2/6] NGSTACK-1017 extend config --- .../CompilerPass/JwtRefreshCompilerPass.php | 7 ++++--- src/DependencyInjection/Configuration.php | 4 ++++ src/NetgenApiPlatformExtrasBundle.php | 7 +++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/DependencyInjection/CompilerPass/JwtRefreshCompilerPass.php b/src/DependencyInjection/CompilerPass/JwtRefreshCompilerPass.php index ed98019..83bccd7 100644 --- a/src/DependencyInjection/CompilerPass/JwtRefreshCompilerPass.php +++ b/src/DependencyInjection/CompilerPass/JwtRefreshCompilerPass.php @@ -138,12 +138,13 @@ public function process(ContainerBuilder $container): void sprintf('lexik_jwt_authentication.cookie_provider.%s', $jwtCookieName), ContainerInterface::NULL_ON_INVALID_REFERENCE, ), - $refreshTtl, + $refreshCookieConfig, + $jwtAuthorizationHeaderPrefix, $refreshSingleUse, $jwtAuthorizationHeaderName, - $jwtAuthorizationHeaderPrefix, $jwtCookieName, - $refreshCookieConfig, + $refreshTtl, + $this->resolveBoolParameter($container, sprintf('%s.user_aware', self::BASE_FEATURE_PATH), false), ]); $container->setDefinition( diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index dc43ff4..32ce8c8 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -52,6 +52,10 @@ public function getConfigTreeBuilder(): TreeBuilder ->defaultFalse() ->info('Will refresh jwt header during request cycle if valid refresh token present and enabled.') ->end() + ->booleanNode('user_aware') + ->defaultFalse() + ->info('Will check if user provider supports class refresh token was created from.') + ->end() ->arrayNode('ignored_routes') ->scalarPrototype()->end() ->defaultValue([]) diff --git a/src/NetgenApiPlatformExtrasBundle.php b/src/NetgenApiPlatformExtrasBundle.php index d532f9c..d68f9b2 100644 --- a/src/NetgenApiPlatformExtrasBundle.php +++ b/src/NetgenApiPlatformExtrasBundle.php @@ -12,8 +12,15 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; +use function dirname; + final class NetgenApiPlatformExtrasBundle extends Bundle { + public function getPath(): string + { + return dirname(__DIR__); + } + public function build(ContainerBuilder $container): void { $container From 654f7d1f7138e1001fec221372c8986a92dd9947 Mon Sep 17 00:00:00 2001 From: Jakov Knezovic Date: Thu, 26 Feb 2026 10:25:35 +0100 Subject: [PATCH 3/6] NGSTACK-1017 adjust refresh service logic --- src/Service/TokenRefreshService.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Service/TokenRefreshService.php b/src/Service/TokenRefreshService.php index 2120ef5..15ea1c9 100644 --- a/src/Service/TokenRefreshService.php +++ b/src/Service/TokenRefreshService.php @@ -11,6 +11,7 @@ use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface; use Netgen\ApiPlatformExtras\JwtRefresh\TokenSourceType; use Netgen\ApiPlatformExtras\JwtRefresh\ValueObject\RefreshToken; +use Netgen\ApiPlatformExtras\Model\UserAwareRefreshToken; use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\Request; @@ -36,12 +37,13 @@ public function __construct( private JWTTokenManagerInterface $jwtTokenManager, private ServiceLocator $providerLocator, private ?JWTCookieProvider $jwtCookieProvider, - private int $refreshTtl, + private array $refreshCookieSettings, + private string $jwtHeaderPrefix, private bool $refreshSingleUse, private string $jwtHeaderName, - private string $jwtHeaderPrefix, private string $jwtCookieName, - private array $refreshCookieSettings, + private int $refreshTtl, + private bool $userAware, ) { $this->refreshCookieSettings = array_merge([ 'enabled' => false, @@ -93,7 +95,14 @@ public function refresh( return; } - $username = $refreshToken->getUsername(); + if ($this->userAware && !$refreshToken instanceof UserAwareRefreshToken) { + return; + } + + if ($this->userAware && !$provider->supportsClass($refreshToken->getClass())) { + $username = $refreshToken->getUsername(); + } + if (!is_string($username) || $username === '') { return; } From 1dabaa375c5c2ea697c7d5b5e9a62e917ac87e16 Mon Sep 17 00:00:00 2001 From: Jakov Knezovic Date: Thu, 26 Feb 2026 10:28:28 +0100 Subject: [PATCH 4/6] NGSTACK-1017 adjust readme file --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index faf3537..af1eec9 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Configuration (config/packages/api_platform_extras.yaml): ```yaml api_platform_extras: features: + # NOT IMPLEMENTED YET http_cache: enabled: false schema_decoration: @@ -13,12 +14,14 @@ api_platform_extras: default_required_properties: false #Add @id as an optional property to all POST, PUT and PATCH schemas. jsonld_update_schema: false + # NOT IMPLEMENTED YET simple_normalizer: enabled: false jwt_refresh: enabled: false auto_refresh_cookie: false auto_refresh_header: false + user_aware: false ignored_routes: [] ignored_paths: [] allowed_firewalls: [] @@ -41,6 +44,8 @@ Enable features by setting the corresponding flag to true. If both auto-refresh flags are `false`, behavior is effectively the same as feature disabled. +`user_aware` defaults to `false`. When enabled, refresh token handling validates that the selected user provider supports the user class stored on the refresh token. + ### Related bundle config JWT/refresh token names and header prefix are taken from Lexik/Gesdinet config (with bundle defaults): @@ -52,6 +57,29 @@ JWT/refresh token names and header prefix are taken from Lexik/Gesdinet config ( When Lexik extractor parameters are not exposed as container parameters, values are read from Lexik extractor service definition arguments. +### Refresh token entity + +When using custom refresh token entities, extend the bundle entity: + +```php + Date: Thu, 26 Feb 2026 10:34:00 +0100 Subject: [PATCH 5/6] NGSTACK-1017 fix phpstan --- src/Model/UserAwareRefreshToken.php | 6 ++++-- src/Service/TokenRefreshService.php | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Model/UserAwareRefreshToken.php b/src/Model/UserAwareRefreshToken.php index 7656063..13e0485 100644 --- a/src/Model/UserAwareRefreshToken.php +++ b/src/Model/UserAwareRefreshToken.php @@ -13,8 +13,10 @@ abstract class UserAwareRefreshToken extends AbstractRefreshToken public static function createForUserWithTtl(string $refreshToken, UserInterface $user, int $ttl): static { - return parent::createForUserWithTtl($refreshToken, $user, $ttl) - ->setClass($user::class); + /** @var static $token */ + $token = parent::createForUserWithTtl($refreshToken, $user, $ttl); + + return $token->setClass($user::class); } public function getClass(): string diff --git a/src/Service/TokenRefreshService.php b/src/Service/TokenRefreshService.php index 15ea1c9..6235c8a 100644 --- a/src/Service/TokenRefreshService.php +++ b/src/Service/TokenRefreshService.php @@ -100,9 +100,11 @@ public function refresh( } if ($this->userAware && !$provider->supportsClass($refreshToken->getClass())) { - $username = $refreshToken->getUsername(); + return; } + $username = $refreshToken->getUsername(); + if (!is_string($username) || $username === '') { return; } From 113fcbc1106254fd9b6972a08bf05a06a2dd46c8 Mon Sep 17 00:00:00 2001 From: Jakov Knezovic Date: Thu, 26 Feb 2026 10:39:33 +0100 Subject: [PATCH 6/6] NGSTACK-1017 fix phpstan again --- src/Service/TokenRefreshService.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Service/TokenRefreshService.php b/src/Service/TokenRefreshService.php index 6235c8a..0611af9 100644 --- a/src/Service/TokenRefreshService.php +++ b/src/Service/TokenRefreshService.php @@ -95,12 +95,14 @@ public function refresh( return; } - if ($this->userAware && !$refreshToken instanceof UserAwareRefreshToken) { - return; - } + if ($this->userAware) { + if (!$refreshToken instanceof UserAwareRefreshToken) { + return; + } - if ($this->userAware && !$provider->supportsClass($refreshToken->getClass())) { - return; + if (!$provider->supportsClass($refreshToken->getClass())) { + return; + } } $username = $refreshToken->getUsername();