JWTRefreshTokenBundle icon indicating copy to clipboard operation
JWTRefreshTokenBundle copied to clipboard

Symfony 6 Unable to find the controller for path "/api/token/refresh". The route is wrongly configured.

Open Bohilc opened this issue 2 years ago • 27 comments

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:

# ...
 firewalls:
        api_token_refresh:
            pattern: ^/api/token/refresh
            stateless: true
            refresh_jwt: ~

        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        login:
            pattern: ^/api/login
            stateless: true
            json_login:
                check_path: /api/login
                username_path: uusr_login
                password_path: uusr_pass
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure

        api:
            pattern: ^/api/
            stateless: true
            provider: app_user_provider
            jwt: ~

        main:
            provider: app_user_provider
            logout:
                path: app_logout
# ...

router.yaml:


api_login:
    path: /api/login
    methods: ['POST']

gesdinet_jwt_refresh_token:
    path: /api/token/refresh

Bohilc avatar Mar 22 '22 18:03 Bohilc

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: ~

mv-developer avatar Mar 24 '22 16:03 mv-developer

Same issue here, the comment from @mv-developer didn't solved the problem...

matmkian avatar Mar 28 '22 14:03 matmkian

Same issue here.

DougHayward avatar Mar 29 '22 11:03 DougHayward

Same issue. Did someone get the idea how to fix it?

gregurco avatar Apr 06 '22 18:04 gregurco

Same issue on 5.4

andrconstruction avatar Apr 07 '22 04:04 andrconstruction

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.

See 1 and 2.

Jayfrown avatar Apr 07 '22 09:04 Jayfrown

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

AimSai59 avatar Aug 08 '22 01:08 AimSai59

Work well with configuration :

    refresh_jwt:
        refresh_jwt:
            check_path: /api/token/refresh
        provider:  app_user_provider

youassi avatar Sep 29 '22 13:09 youassi

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

irmantas avatar Oct 21 '22 07:10 irmantas

@youassi that is working, thanks!

fico7489 avatar Feb 28 '23 14:02 fico7489

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 :

  • { path: ^/api/token/refresh, roles: PUBLIC_ACCESS }

mouataz1 avatar Mar 28 '23 21:03 mouataz1

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. 👍🏾

SergeMezui16 avatar Apr 10 '23 15:04 SergeMezui16

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

maximanek avatar Apr 11 '23 21:04 maximanek

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

jay0x avatar Jun 01 '23 14:06 jay0x

@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 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. 👍🏾

EnterVPL avatar Jun 20 '23 09:06 EnterVPL

Work well with configuration :

    refresh_jwt:
        refresh_jwt:
            check_path: /api/token/refresh
        provider:  app_user_provider

@youassi Thanks a lot work for me

Servialux avatar Nov 11 '23 09:11 Servialux

Hello, when will this be officially fixed?

Inscure avatar Mar 27 '24 11:03 Inscure

Hello, when will this be officially fixed? I don't if they really consider that it has been to be fixed!

SergeMezui16 avatar Mar 27 '24 12:03 SergeMezui16

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:

  1. Your routes.yaml contains something like this:
routes.yaml
api_token_refresh:
    path: /api/token/refresh
  1. Your security.yaml contains something like this:
security.yaml
security:

    firewalls:
        api:
            pattern: ^/api
            stateless: true
            entry_point: jwt
            jwt: ~
            refresh_jwt:
                check_path: api_token_refresh

    access_control:
        - { path: ^/api/token, roles: PUBLIC_ACCESS }

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"}

Jayfrown avatar Mar 27 '24 15:03 Jayfrown

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

bobas01 avatar Apr 01 '24 15:04 bobas01

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 ?

SergeMezui16 avatar Apr 01 '24 16:04 SergeMezui16

`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: ^/admin, roles: ROLE_ADMIN } - { 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

bobas01 avatar Apr 01 '24 16:04 bobas01

@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 avatar Apr 01 '24 19:04 bobas01

@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 avatar Apr 01 '24 19:04 SergeMezui16

@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 avatar Apr 01 '24 19:04 bobas01

@bobas01 My bad. I put main and api_token_refresh firewalls under api instead of firewalls 👎🏾 ! You can try this again i change it ;)!

SergeMezui16 avatar Apr 01 '24 19:04 SergeMezui16