23

I am tyring to set up symfony4 api JSON login by JWT. The api platform core bundle is installed and I followed this instruction: https://api-platform.com/docs/core/jwt/

I created the custom user provider as described. By opening the URL /api/login_check the error message "Unable to find the controller for path "/api/login_check". The route is wrongly configured." occurs.

By sending a POST request I get the error page in html.

This is my routes.yaml:

#index:
#    path: /
#    controller: App\Controller\DefaultController::index
api_login_check:
    path: /api/login_check

And here is my security.yaml:

security:
    encoders:
        App\Security\User\WebserviceUser: bcrypt
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        webservice:
          id: App\Security\User\WebserviceUserProvider
        in_memory: { memory: ~ }
        main:
          entity: { class: App\Entity\User, property: email }
    firewalls:
        login:
            pattern:  ^/api/login
            stateless: true
            anonymous: true
            provider: webservice
            json_login:
                check_path: /api/login_check
                username_path: email
                password_path: password
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure
        api:
            pattern: ^/api
            provider: webservice
            stateless: true
            guard:
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: ~

            # activate different ways to authenticate

            # http_basic: true
            # https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate

            # form_login: true
            # https://symfony.com/doc/current/security/form_login_setup.html

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        - { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/api,       roles: IS_AUTHENTICATED_FULLY }

bin/console debug:route returns:

 --------------------------- -------- -------- ------ ------------------------------------- 
  Name                        Method   Scheme   Host   Path                                 
 --------------------------- -------- -------- ------ ------------------------------------- 
  api_entrypoint              ANY      ANY      ANY    /api/{index}.{_format}               
  api_doc                     ANY      ANY      ANY    /api/docs.{_format}                  
  api_jsonld_context          ANY      ANY      ANY    /api/contexts/{shortName}.{_format}  
  api_users_get_collection    GET      ANY      ANY    /api/users.{_format}                 
  api_users_post_collection   POST     ANY      ANY    /api/users.{_format}                 
  api_users_get_item          GET      ANY      ANY    /api/users/{id}.{_format}            
  api_users_delete_item       DELETE   ANY      ANY    /api/users/{id}.{_format}            
  api_users_put_item          PUT      ANY      ANY    /api/users/{id}.{_format}            
  _twig_error_test            ANY      ANY      ANY    /_error/{code}.{_format}             
  api_login_check             ANY      ANY      ANY    /api/login_check                     
 --------------------------- -------- -------- ------ -------------------------------------

Does anybody know what my mistake is?

A.L
  • 10,259
  • 10
  • 67
  • 98
user3684098
  • 349
  • 1
  • 3
  • 18

9 Answers9

19

I ran into the same issue, and it appeared that the header

    Content-Type: application/json

must be added when you requesting /api/login_check

  • Yes, thank you so much. This resolves the error. Buy why is this requirement. Is this requirement from Symfony 4 or JWT token bundle? – Caslav Sabani Aug 26 '19 at 10:04
  • 1
    I think this is required by Symfony - the documentation for json_login setup says: [Now, when you make a POST request, with the header Content-Type: application/json, to the /login URL with the following JSON document as the body, the security system intercepts the request and initiates the authentication process](https://symfony.com/doc/current/security/json_login_setup.html). So it seems that if you don't specify the header, the request will not be intercepted by security system. – Alexander Tretyak Aug 27 '19 at 08:20
7

Comment in security.yaml those lines:

main:
anonymous: true
Moris Finkel
  • 197
  • 2
  • 5
4

Had same issue, but somehow when I changed order of nested config in firewall it solved that issue and lexik jwt started to work. my config:

security:
    encoders:
        App\Entity\User:
            algorithm: bcrypt

 # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
    # used to reload user from session & other features (e.g. switch_user)
    app_user_provider:
        entity:
            class: App\Entity\User
            property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false


        # activate different ways to authenticate
        login:
            pattern:  ^/api/login
            stateless: true
            anonymous: true
            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
            guard:
                authenticators:
                - lexik_jwt_authentication.jwt_token_authenticator
        main:
            anonymous: true


        # http_basic: true
        # https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate

        # form_login: true
        # https://symfony.com/doc/current/security/form_login_setup.html

# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
    access_control:
        - { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: /api/user/activate, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/api,       roles: IS_AUTHENTICATED_FULLY }

routes.yaml

app:
  path: /{params}
  controller: App\Controller\DefaultController::index
  requirements:
       params: "^(?!admin|api).+"

api_login_check:
   path: /api/login
   methods: [POST]
1

Well, I think you don't have to re-define the path:

api_login_check:
    path: /api/login_check

remove that and test it.

and check if this path: /api/login_check is correct, because that is not the standard login_check from FOSUserBundle.

Hope this helps.

Anjana Silva
  • 8,353
  • 4
  • 51
  • 54
Sergio Susa
  • 249
  • 3
  • 7
1

It seems like you haven't declared a Controller for this path:

api_login_check:
    path: /api/login_check
    controller: App\Controller\AuthenticationController::login
Igor Shumichenko
  • 394
  • 3
  • 12
0

Use route debugger to see if the route is here:

php bin/console debug:route | grep login_check

If not, add it!

Inside route.yml:

api_login_check:
    path: /api/login_check

(or check the configuration of the bundle that should add it for you).

Thomas Decaux
  • 21,738
  • 2
  • 113
  • 124
  • I can't speak for the original poster, but when I do this, the route shows up. Despite that, I still get the message "Unable to find the controller for path /api/login_check. The route is wrongly configured" when trying to access the route using Postman. It seems like a good fix would be to explicitly set the controller to hit in routing.yml or route.yml. I just don't know which controller to use. – Mayor of the Plattenbaus Nov 01 '19 at 12:48
0

My security.yaml is similar to yours, you may incorrectly test the result of your configuration, reset the url, username and password.

Test this:

curl -X POST -H "Content-Type: application/json" http://localhost/api/login_check -d '{"username":"USER", "password":"PASSWORD"}

this is my security:

security:
encoders:
    App\Entity\User:
        algorithm: auto

# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
    # used to reload user from session & other features (e.g. switch_user)
    app_user_provider:
        entity:
            class: App\Entity\User
            property: username
firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false

    login:
        pattern:  ^/api/login
        stateless: true
        anonymous: true
        json_login:
            check_path:               /api/login_check
            success_handler:          lexik_jwt_authentication.handler.authentication_success
            failure_handler:          lexik_jwt_authentication.handler.authentication_failure

    api:
        pattern:   ^/api
        stateless: true
        guard:
            authenticators:
                - lexik_jwt_authentication.jwt_token_authenticator

access_control:
    - { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/api,       roles: IS_AUTHENTICATED_FULLY }
0

The following scenario worked for me after some sleepless nights.

I initially had issues connecting to Postman, clicking on the header and changing it to Application/JSON was not enough as I keep getting ORM/Doctrine errors. what worked for me was that I used deprecated functions in one of my PHP classes.

I simply went to my log file Var/log/dev.log and found this error:

php.CRITICAL: Uncaught Error: Cannot assign Doctrine\ORM\PersistentCollection to property Guess\Domain\Player\Player::$guesses of type Doctrine\Common\Collections\ArrayCollection

Further research shows that I used the ArrayCollecton object which has been deprecated to Collection, so change the ArrayCollection to just Collection including the getter and setter method and try again.

This worked for me now and am so happy.

Reference: Doctrine assignment error: Cannot assign Doctrine\ORM\PersistentCollection to property

This could go a long way to help someone in the near future.

Olasunkanmi
  • 902
  • 15
  • 23
0

for me all I had to do was putting the login and api firewalls above the main one:

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

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

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

main:
    form_login:
        # "login" is the name of the route created previously
        login_path: app_login
        check_path: app_login
        enable_csrf: true