Open Bohilc opened 2 years ago
You need to add provider to api_token_refresh
Ex:
api_token_refresh:
pattern: ^/api/token/refresh
stateless: true
provider: app_user_provider
refresh_jwt: ~
Same issue here, the comment from @mv-developer didn't solved the problem...
Same issue here.
Same issue. Did someone get the idea how to fix it?
Same issue on 5.4
This happens because in the latest release the authenticator only reports support for requests where the refresh token is present. A fix has been merged (just now) but has not yet been included in a release.
So sending an empty request will result in a 404, but using the route as intended (ie. sending the refresh token with the request in a manner the extractor can find it) should work as expected.
Until the next release, a dirty work-around could be to add the following to your route configuration:
api_token_refresh:
path: /api/token/refresh
controller: gesdinet.jwtrefreshtoken::refresh
In this case, using the route as intended will still trigger the authenticator system (and not use the defined controller) but any request to the same path where the authenticator does not trigger, will end up using the controller instead of returning a 404. Just don't forget to remove the controller config when a new version is released.
after a LOT of debugging, I found that the solution is to simply add check_path: gesdinet_jwt_refresh_token
in the security.yaml, like this:
firewalls:
refresh:
// ...
refresh_jwt:
check_path: gesdinet_jwt_refresh_token
Work well with configuration :
refresh_jwt:
refresh_jwt:
check_path: /api/token/refresh
provider: app_user_provider
If anyone have route issues configuring this with SF 6.1, here is my solution:
Add users provider to refresh firewall, configure new route with different path than /api/token/refresh
. For example:
# security.yaml
firewalls:
# ...
refresh:
provider: my_user_provider
refresh_jwt:
check_path: api_refresh_token
# routes.yaml
api_refresh_token:
path: /api/token/renew
@youassi that is working, thanks!
hello, i dont know if u still need the solution , any way this ts my configuration and it works jut fine : symfony 6.2 on the routes.yaml file :
api_refresh_token: path: /api/token/refresh
on the security.yaml file this is my firewall :
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
json_login:
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
logout:
path: /logout
api_token_refresh:
pattern: ^/api/token/refresh
stateless: true
refresh_jwt:
check_path: /api/token/refresh
api:
pattern: ^/api
stateless: true
jwt: ~
main:
custom_authenticators:
- App\Security\MyGoogleAuthenticator
- App\Security\MyLinkedinAuthenticator
entry_point: App\Security\MyGoogleAuthenticator
also do not forget to add the access control :
Hi !
I recently had the same problem with Symfony 6.2 and PHP 8.1.
Fortunately, I got the solution.
It seems that the refresh route has been configured to accept only some pattern of url.
I test some url for this route and the controller was not the problem. The problem came from the path of our routes.
By the look of it, routes path like /auth/refresh/token
are bad where routes path like api/refresh/token
(whith is recommended by the bundle in doc), refresh/token
or token/refresh
are good !
I don't take more time to test which path occur an error or not but I think the problem is that the bundle auto configure some routes path and not others.
That is my configuration :
# route.yaml
# ...
api_refresh_token:
path: /token/refresh
methods: [POST]
# ...
# security.yaml
security:
# ...
firewalls:
# ...
api_token_refresh:
pattern: /token/refresh
stateless: true
provider: app_user_provider # provider in database
refresh_jwt:
check_path: api_refresh_token
# ...
# ...
access_control:
# ...
- { path: ^/token/refresh$, roles: PUBLIC_ACCESS }
# ...
# ...
I have removed the path configuration in config/routes/gesdinet_jwt_refresh_token.yaml
created by Symfony Recipes, with this configuration it will not work again. I recommend you to remove this file because it isn't helpful anymore.
Then, my configuration is like this :
# gesdinet_jwt_refresh_token:
# path: /token/refresh
# ...
Now, it works so good ! So. That solution is just temporary, I guest they will fix it. I wish I helped you. 👍🏾
Hello i've done my configuration like @SergeMezui16. And its working just fine, but when I add prefix /api/ to match rest of my app i still got wrongly configured route exception
Hi guys. I tried to follow @SergeMezui16 instructions... and it didn't work :( I'm getting Unable to find the controller for path "/token/refresh" The route is wrongly configured.
PHP 8.2.6 api-platform v3.1.12 symfony 6.2 lexik/jwt-authentication-bundle v2.19.0 gesdinet/jwt-refresh-token-bundle v1.1.1
Fortunately, I got the solution too :)
security.yaml
# ...
firewalls:
# ...
main:
json_login:
# ...
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
# ...
refresh_jwt:
check_path: api_refresh_token
entry_point: 'lexik_jwt_authentication.security.authentication.entry_point'
routes.yaml
# ...
api_refresh_token:
path: /api/token/refresh
methods: [POST]
File config/routes/gesdinet_jwt_refresh_token.yaml
was deleted
@SergeMezui16 Very very thanks! ❤️ Your solution works! 😀
Hi !
I recently had the same problem with Symfony 6.2 and PHP 8.1.
Fortunately, I got the solution.
It seems that the refresh route has been configured to accept only some pattern of url. I test some url for this route and the controller was not the problem. The problem came from the path of our routes. By the look of it, routes path like
/auth/refresh/token
are bad where routes path likeapi/refresh/token
(whith is recommended by the bundle in doc),refresh/token
ortoken/refresh
are good !I don't take more time to test which path occur an error or not but I think the problem is that the bundle auto configure some routes path and not others.
That is my configuration :
# route.yaml # ... api_refresh_token: path: /token/refresh methods: [POST] # ...
# security.yaml security: # ... firewalls: # ... api_token_refresh: pattern: /token/refresh stateless: true provider: app_user_provider # provider in database refresh_jwt: check_path: api_refresh_token # ... # ... access_control: # ... - { path: ^/token/refresh$, roles: PUBLIC_ACCESS } # ... # ...
I have removed the path configuration in
config/routes/gesdinet_jwt_refresh_token.yaml
created by Symfony Recipes, with this configuration it will not work again. I recommend you to remove this file because it isn't helpful anymore. Then, my configuration is like this :# gesdinet_jwt_refresh_token: # path: /token/refresh # ...
Now, it works so good ! So. That solution is just temporary, I guest they will fix it. I wish I helped you. 👍🏾
Work well with configuration :
refresh_jwt: refresh_jwt: check_path: /api/token/refresh provider: app_user_provider
@youassi Thanks a lot work for me
Hello, when will this be officially fixed?
Hello, when will this be officially fixed? I don't if they really consider that it has been to be fixed!
Hello, when will this be officially fixed?
This has, in fact, been officially fixed @Inscure
https://github.com/markitosgv/JWTRefreshTokenBundle/pull/303 has been merged on April 7, 2022 and any release >= v1.1.1 contains the fix.
Make sure that:
routes.yaml
contains something like this:security.yaml
contains something like this:Requests to your defined route will hit the RefreshTokenAuthenticator
:
❯ curl -k -X GET https://localhost/api/token/refresh
{"code":401,"message":"Missing JWT Refresh Token"}
❯ curl -k -X POST https://localhost/api/token/refresh
{"code":401,"message":"Missing JWT Refresh Token"}
hi everywone, i try all youre solution for to have the same result when i want to migrate :
Unrecognized options "secret, lifetime, path" under "security.firewalls.remember_me". Available options are "access_denied_handler", "access_denied_url", "access_token", "context", "custom_authenticators
", "entry_point", "form_login", "form_login_ldap", "host", "http_basic", "http_basic_ldap", "json_login", "json_login_ldap", "jwt", "lazy", "login_link", "login_throttling", "logout", "methods", "pattern
", "provider", "refresh_jwt", "remember_me", "remote_user", "request_matcher", "required_badges", "security", "stateless", "switch_user", "user_checker", "x509".
If someone have an idea thks
hi everywone, i try all youre solution for to have the same result when i want to migrate : Unrecognized options "secret, lifetime, path" under "security.firewalls.remember_me". Available options are "access_denied_handler", "access_denied_url", "access_token", "context", "custom_authenticators ", "entry_point", "form_login", "form_login_ldap", "host", "http_basic", "http_basic_ldap", "json_login", "json_login_ldap", "jwt", "lazy", "login_link", "login_throttling", "logout", "methods", "pattern ", "provider", "refresh_jwt", "remember_me", "remote_user", "request_matcher", "required_badges", "security", "stateless", "switch_user", "user_checker", "x509".
If someone have an idea thks
Can you share your entire configuraion ? security.yaml and route.yaml ?
`security: enable_authenticator_manager: true
password_hashers: Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: "auto"
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
jwt:
lexik_jwt:
class: App\Entity\User
firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false login: pattern: ^/api/login stateless: true json_login: check_path: /api/login success_handler: lexik_jwt_authentication.handler.authentication_success failure_handler: lexik_jwt_authentication.handler.authentication_failure provider: app_user_provider
api:
pattern: ^/api
stateless: true
provider: jwt
jwt: ~
remember_me:
secret: "%kernel.secret%"
lifetime: 604800
path:
/
access_control:
{ path: ^/profile, roles: ROLE_USER } when@test: security: password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: algorithm: auto cost: 4 time_cost: 3 memory_cost: 10 ` route.yaml
controllers: resource: path: ../src/Controller/ namespace: App\Controller type: attribute api_login_check: path: /api/login_check api_refresh_token: path: /api/token/refresh
@SergeMezui16 thks dude it's working. I put under api but i don't know if is the good one. But i don't have error
@bobas01 You shouldn't put your remember_me configuration at the same level with firewalls but under a specific firewall as said in symfony doc.
Your security.yaml
configuration should look like this:
# security.yaml
security:
# ....
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
jwt:
lexik_jwt:
class: App\Entity\User
firewalls:
#...
login:
pattern: ^/api/login
stateless: true
provider: app_user_provider
json_login:
check_path: /api/login
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
api:
pattern: ^/api
stateless: true
provider: jwt
jwt: ~
# Delete all cookies on logout
logout:
path: api_token_invalidate
delete_cookies:
refresh_token:
path: /
samesite: none
token:
path: /
samesite: none
# if you use jwt refresh token
api_token_refresh:
pattern: ^/token/refresh$
stateless: true
provider: app_user_provider
user_checker: App\Security\UserChecker
refresh_jwt:
check_path: api_refresh_token
main:
lazy: true
provider: app_user_provider
stateless: true
remember_me:
secret: "%kernel.secret%"
lifetime: 604800
# ...
And your route.yaml
:
# route.yaml
# ...
api_refresh_token:
path: /token/refresh
methods: [POST]
# ...
@SergeMezui16 i try your code and i come back with th same error In ArrayNode.php line 327:
Unrecognized option "api_token_refresh" under "security.firewalls.api". Available options are "access_denied_handler", "access_denied_url", "access_token", "context", "custom_authenticators", "entry_poin
t", "form_login", "form_login_ldap", "host", "http_basic", "http_basic_ldap", "json_login", "json_login_ldap", "jwt", "lazy", "login_link", "login_throttling", "logout", "methods", "pattern", "provider",
"refresh_jwt", "remember_me", "remote_user", "request_matcher", "required_badges", "security", "stateless", "switch_user", "user_checker", "x509".
@bobas01 My bad. I put main
and api_token_refresh
firewalls under api instead of firewalls 👎🏾 ! You can try this again i change it ;)!
For those who is facing a similar problem, check if any other firewall doesn't override your refresh firewall. E.g. I had this config before updating to 5.4 style:
api_auth:
pattern: ^(\/[a-z]{2})?/api/token/(refresh|verify)
stateless: false
api_refresh:
pattern: ^(\/[a-z]{2})?/api/token/refresh
stateless: false
provider: database_users
refresh_jwt:
check_path: gesdinet_jwt_refresh_token
I was struggling for hours until I noticed that api_auth
firewall matched the refresh path, thus api_refresh
firewall didn't work at all. So silly mistake but I suppose someone may doing same mistake without realizing it :)
@Bohilc This document outlines the solution to a common issue with JWT refresh tokens and user provider configuration in Symfony applications, particularly after Symfony 5.
The previous configuration often relied on deprecated settings and lacked a robust user provider implementation. This guide provides a corrected and improved approach.
Previous configurations might have used deprecated. bundle settings or had incomplete user provider implementations, leading to issues with refreshing JWT tokens.
Security Configuration (config/packages/security.yaml
)
security:
providers:
app_user_provider: # Define your user provider
entity:
class: App\Entity\User
property: username # Or email, adjust as needed
firewalls:
main:
# ... other firewall settings
provider: app_user_provider # Reference the provider
# ... your authentication mechanisms (e.g., login_form, api_token)
access_control:
- { path: ^/api/token/refresh, roles: PUBLIC_ACCESS } # Public access to refresh endpoint
Routing Configuration (config/routes.yaml)
refresh_jwt:
path: /api/token/refresh
controller: App\Controller\RefreshTokenController::refresh # Replace with your actual controller and method
User Provider (src/Security/UserProvider.php)
<?php
namespace App\Security;
use App\Entity\User;
use App\Repository\UserRepository;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class UserProvider implements UserProviderInterface
{
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
/**
* Symfony calls this method if you use features like switch_user
* or remember_me.
*
* If you're not using these features, you do not need to implement
* this method.
*
* @throws UnsupportedUserException if the account is not supported
*/
public function refreshUser(UserInterface $user): UserInterface
{
if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', $user::class));
}
return $this->loadUserByIdentifier($user->getUserIdentifier());
}
/**
* Whether this provider supports the given user class.
*
* @param string $class
* @return bool
*/
public function supportsClass(string $class): bool
{
return User::class === $class || is_subclass_of($class, User::class);
}
/**
* @param string $identifier
* @return UserInterface
*/
public function loadUserByIdentifier(string $identifier): UserInterface
{
if (is_numeric($identifier)){
$user = $this->userRepository->find($identifier); // Use the correct field (username, email, etc.)
}
else{
$user = $this->userRepository->findOneBy(['username'=>$identifier]); // Use the correct field (username, email, etc.)
}
if (null === $user) {
throw new UserNotFoundException(sprintf('User "%s" not found.', $identifier));
}
return $user;
}
}
@Bohilc if you had any other question you can ask here.
In symfony 6 refresh token not working properly because it unable to find the controller. Do you have any solution for this case ?
security.yaml -> firewalls:
router.yaml: