Lexikjwtauthenticationbundle: How the Bundle intercept the token and what's /login_check ?

Created on 1 Nov 2016  路  7Comments  路  Source: lexik/LexikJWTAuthenticationBundle

Hi,

I'm certainly stupid but, it's some hours that I'm looking to understand how the security layer will get the token when the client send it.

And how with your default config you create the token ?
Because if I follow just what you writed, you indicate that we need to put in the routing.yml :
login_check:
path: /login_check

But this path refer to which controller ?

And after that, when the client send me the token, how this one will be "analyze" to know which user is it ?

I'm lost :(

Thanks for your help

Most helpful comment

Hi @Namiro,

I'm certainly stupid but, it's some hours that I'm looking to understand how the security layer will get the token when the client send it.

There's nothing stupid here :) Looks like a support issue that is more about Symfony in general than this bundle, but let's take it as a good reminder.

Because if I follow just what you writed, you indicate that we need to put in the routing.yml :
login_check:
path: /login_check

But this path refer to which controller ?

In fact, it doesn't refer to a controller.
Instead, any request to this endpoint is intercepted by the Symfony's security layer (provided by the symfony/security component), because you configured a form_login listener on your firewall.
The magic happens here and here.

And after that, when the client send me the token, how this one will be "analyze" to know which user is it ?

This part is handled from our side.

When you configure your JWT protected firewall (using lexik_jwt (1.x legacy) or guard (2.x stable), our authenticator first tries to find a token in the current request using the configured token extractors (default in an Authorization header with Bearer prefix, using the AuthorizationHeaderTokenExtractor).

Then, it uses our built-in token encoder/decoder for decoding the token through our JWTManager. The encoder performs all validity checks that are needed (expiration, signature verification, .. see the encoder itself for details) and, if all is ok, the token's payload is returned, containing the configured user_identity_field as key.

Finally, the value of this key is used for retrieving the user, and if it can be found, it is authenticated.

I'm lost :(

I hope you're less now. Or at least, not more :)
Do not hesitate if you still have some interrogations.

All 7 comments

Hi @Namiro,

I'm certainly stupid but, it's some hours that I'm looking to understand how the security layer will get the token when the client send it.

There's nothing stupid here :) Looks like a support issue that is more about Symfony in general than this bundle, but let's take it as a good reminder.

Because if I follow just what you writed, you indicate that we need to put in the routing.yml :
login_check:
path: /login_check

But this path refer to which controller ?

In fact, it doesn't refer to a controller.
Instead, any request to this endpoint is intercepted by the Symfony's security layer (provided by the symfony/security component), because you configured a form_login listener on your firewall.
The magic happens here and here.

And after that, when the client send me the token, how this one will be "analyze" to know which user is it ?

This part is handled from our side.

When you configure your JWT protected firewall (using lexik_jwt (1.x legacy) or guard (2.x stable), our authenticator first tries to find a token in the current request using the configured token extractors (default in an Authorization header with Bearer prefix, using the AuthorizationHeaderTokenExtractor).

Then, it uses our built-in token encoder/decoder for decoding the token through our JWTManager. The encoder performs all validity checks that are needed (expiration, signature verification, .. see the encoder itself for details) and, if all is ok, the token's payload is returned, containing the configured user_identity_field as key.

Finally, the value of this key is used for retrieving the user, and if it can be found, it is authenticated.

I'm lost :(

I hope you're less now. Or at least, not more :)
Do not hesitate if you still have some interrogations.

Thanks a lot for your help.
But I miss something, I don't know what...

Fot the api/check_login (and for the token decode)
What's wrong in this config :

app/config/security.yml
`
security:
providers:
main:
entity:
class: SOSVeloRepositoryBundleEntityUser
property: email

role_hierarchy:
    ROLE_PARTNER:     [ROLE_USER]
    ROLE_MEMBER:      [ROLE_USER]
    ROLE_ADMIN:       [ROLE_PARTNER, ROLE_MEMBER, ROLE_USER]
    ROLE_SUPER_ADMIN: [ROLE_ADMIN]

encoders:
    SOSVelo\RepositoryBundle\Entity\User:
        algorithm:        sha1
        encode_as_base64: false
        iterations:       1

firewalls:
    # disables authentication for assets and the profiler, adapt it according to your needs
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false

    main:
        anonymous: ~
        #provider:  main
        # activate different ways to authenticate

        # http_basic: ~
        # http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate

        # form_login: ~
        # http://symfony.com/doc/current/cookbook/security/form_login_setup.html

    login:
        pattern:  ^/api/login
        stateless: true
        anonymous: true
        form_login:
            check_path: /api/login_check
            success_handler: lexik_jwt_authentication.handler.authentication_success
            failure_handler: lexik_jwt_authentication.handler.authentication_failure
            require_previous_session: false
            username_parameter: email
            password_parameter: password

    api:
        pattern:   ^/api
        stateless: true
        lexik_jwt:
            authorization_header:
                enabled: true
                prefix:  Bearer
            query_parameter:
                enabled: true
                name:    bearer
        guard:
            authenticators:
                - lexik_jwt_authentication.jwt_token_authenticator

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

`

I suppose that my problems comes from this config file, but I try a lot combination and no one is ok..

My current error is :
Unable to find the controller for path "/api/login_check". The route is wrongly configured.

And I suppose my routing is ok because if I dedicate a Controller to this url, it works.
(I would to work with you lastest version because I saw that you deprecated many thing about the oldest versions.)

I see two issues in your config:

  • You are combining the legacy security configuration with the new one, you need to remove the lexik_jwt key with all its content and keep only guard
  • Your have a main firewall which doesn't have a pattern specified (thus covering ^/, the default value) and allowing anonymous, so you have to either remove it or move it after the login and api ones. The security component takes the first matching firewall from the configured ones, in the same order you set them

After fixing them, it should work

@Namiro can you close this if my previous comment solved your issue?

Hi,

Excuse me for the time to answer but I work on some projects and so I didn't work on my symfony project the last days.

I try with what you told me but it does'nt yet work. But it's not the same problem now. I think the problem is from the password.

I mean, when I save a user with his password, this one is encrypted. (I'm suprise that symfony do it because I configured nothing for it, but it's cool.
So when the autenticator need to check the password, how can it know how was encrypted the password ? Is it something with your encorder ?

My request and the error :
image

I give my current configuration.

security.yml
`

security:
    # http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
    providers:
        main:
            entity:
                class:    SOSVelo\RepositoryBundle\Entity\User
                property: email

    role_hierarchy:
        ROLE_PARTNER:     [ROLE_USER]
        ROLE_MEMBER:      [ROLE_USER]
        ROLE_ADMIN:       [ROLE_PARTNER, ROLE_MEMBER, ROLE_USER]
        ROLE_SUPER_ADMIN: [ROLE_ADMIN]

    encoders:
        SOSVelo\RepositoryBundle\Entity\User:
            algorithm:        sha1
            encode_as_base64: false
            iterations:       1

    firewalls:
        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        #main:
        #    anonymous: ~
            #provider:  main
            # activate different ways to authenticate

            # http_basic: ~
            # http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate

            # form_login: ~
            # http://symfony.com/doc/current/cookbook/security/form_login_setup.html

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

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

    access_control:
        - { path: ^/api/login_check, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/api,       roles: IS_AUTHENTICATED_REMEMBERED }

`

config.yml
`

lexik_jwt_authentication:
    # ssh private key path
    private_key_path: %jwt_private_key_path%
    # ssh public key path
    public_key_path:  %jwt_public_key_path%
    # ssh key pass phrase
    pass_phrase:      %jwt_key_pass_phrase%
    # token ttl
    token_ttl:        %jwt_token_ttl%
    # key under which the user identity will be stored in the token payload
    user_identity_field: email

    # token encoding/decoding settings
    encoder:
        # token encoder/decoder service - default implementation based on the namshi/jose library
        service: lexik_jwt_authentication.encoder.default
        # crypto engine used by the encoder service
        crypto_engine: openssl
        # encryption algorithm used by the encoder service
        signature_algorithm: RS256

    # token extraction settings
    token_extractors:
        authorization_header:      # look for a token as Authorization Header
            enabled: true
            prefix:  Bearer
            name:    Authorization
        cookie:                    # check token in a cookie
            enabled: false
            name:    BEARER
        query_parameter:           # check token in query string parameter
            enabled: false
            name:    bearer

`

Thanks yet for your help

Ok, your first issue has indeed be fixed as it is no more a Route wrongly configured error.

However I'm unable to reproduce your last issue. Would you consider forking https://github.com/chalasr/lexik-jwt-authentication-sandbox for reproducing it? So we could investigate directly.

Okay. I close this one and thanks for your help.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mflasquin picture mflasquin  路  5Comments

christophe-mailfert picture christophe-mailfert  路  5Comments

ghost picture ghost  路  5Comments

ndoulgeridis picture ndoulgeridis  路  3Comments

tsdevelopment picture tsdevelopment  路  4Comments