Lexikjwtauthenticationbundle: Check user token on unprotected route?

Created on 16 Jan 2017  路  6Comments  路  Source: lexik/LexikJWTAuthenticationBundle

Is there anyway to check for user on unprotected route in case they provide the token? The idea is that I want to get user login status everywhere on the site without getting JWT expired / invalid if the requested route is not protected.

Most helpful comment

Hello,

There are different ways to achieve this, the simplest being to configure the jwt listener (guard authenticator) on the unprotected firewall, beside the anonymous listener, e.g:

security:
    # ...
    firewalls:
        secure:
            pattern: ^/api
            stateless: true
            guard:
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator

        unsecure:
            pattern: ^/unsecure
            anonymous: true
            stateless: true
            guard:
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator
            # You may have the form login on this one
            #form_login:
            #    check_path: /login
            #    require_previous_session: false
            #    success_handler: lexik_jwt_authentication.handler.authentication_success
            #    failure_handler: lexik_jwt_authentication.handler.authentication_failure

    access_control:
        - { path: ^/unsecure, roles: [IS_AUTHENTICATED_ANONYMOUSLY, IS_AUTHENTICATED_FULLY] }
        - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }

If a valid token is passed, you'll be able to retrieve the user from the controller of your unprotected route through $this->getUser(), if no token was passed, it will be null.
One thing to be aware of: If someone sends an invalid token to your unprotected route, he will get a 401 failure response as for the secured firewall (exceptions are thrown even if you allows anonymous, invalid credentials should never be passed).

Hope this helps you.

All 6 comments

Hello,

There are different ways to achieve this, the simplest being to configure the jwt listener (guard authenticator) on the unprotected firewall, beside the anonymous listener, e.g:

security:
    # ...
    firewalls:
        secure:
            pattern: ^/api
            stateless: true
            guard:
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator

        unsecure:
            pattern: ^/unsecure
            anonymous: true
            stateless: true
            guard:
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator
            # You may have the form login on this one
            #form_login:
            #    check_path: /login
            #    require_previous_session: false
            #    success_handler: lexik_jwt_authentication.handler.authentication_success
            #    failure_handler: lexik_jwt_authentication.handler.authentication_failure

    access_control:
        - { path: ^/unsecure, roles: [IS_AUTHENTICATED_ANONYMOUSLY, IS_AUTHENTICATED_FULLY] }
        - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }

If a valid token is passed, you'll be able to retrieve the user from the controller of your unprotected route through $this->getUser(), if no token was passed, it will be null.
One thing to be aware of: If someone sends an invalid token to your unprotected route, he will get a 401 failure response as for the secured firewall (exceptions are thrown even if you allows anonymous, invalid credentials should never be passed).

Hope this helps you.

I actually tried that solution but getting 401 is pretty undesirable since what I want is either null user / anon or user with correct credential to render the page.

You should have a look at https://github.com/lexik/LexikJWTAuthenticationBundle/issues/298, we give a trick to change this behavior. It will be documented soon

It works but it's kind of hacky IMO although i have only skimped through the spec so i'm unsure, or maybe it's how symfony normally works? I don't have much experience in symfony anyhow. Thanks for answering me.

Yeah, the authentication fails at the first exception thrown no matter if the current firewall allows anonymous requests or not, there's no built-in way to bypass that.
You're welcome.

I think i found a solution to handle a request on an unprotected route when the client sends an expired token.

  1. Create your own JwtTokenAuthenticator and decorate the existing JwtTokenAuthenticator
  2. Inject @security.access_map as argument
  3. Check if the request has a role "IS_AUTHENTICATED_ANONYMOUSLY"
  4. Abort JwtTokenAuthenticator process if needed

You can also extend this example by checking if the token is valid and only abort the authenticator when the token is invalid.

The benefit from this solution is not to separate your api endpoints by secure and public access.

The solution in #298 does not work to handle this problem. The code example also does not work in SF4.

public function supports(Request $request)
{
    $supports = $this->decorated->supports($request);
    list($accessMap) = $this->accessMap->getPatterns($request);
    if (is_array($accessMap) && in_array('IS_AUTHENTICATED_ANONYMOUSLY', $accessMap, true)) {
        $supports = false;
    }

    return $supports;
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

tahina4 picture tahina4  路  4Comments

hiromik picture hiromik  路  3Comments

garak picture garak  路  5Comments

christophe-mailfert picture christophe-mailfert  路  5Comments

JuliusKoronci picture JuliusKoronci  路  4Comments