Lexikjwtauthenticationbundle: Getting the JWT Token Not Found Error, But Token Is In Header

Created on 12 Jun 2017  路  12Comments  路  Source: lexik/LexikJWTAuthenticationBundle

I just installed this bundle and installed the sandbox application. I can get a token just fine:

curl -X POST http://sandbox.localhost.com/login_check -d _username=test -d _password=test

This returns:

{"token":"eyJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJleHAiOjE0OTczMDYwMTgsImlhdCI6MTQ5NzMwMjQxOH0.DJjYjQSRxTDKeikHUs1Dsih7WK_7BownP3SA_gVMKCVUjfn9OfaqCp3bXFErqgAPnWtYn6u-LdX5H40ytW9m6j2pHOAAk8sR_pf_8IoWl4WedMniBzHqXs4hPqPVxH9ZJkGhDYnpWZPwHgxq6iOxnHwV_bLO3ZpLtjekOkh-B2EbWFtFbAZN5wIb-GZGLmerkWXDRzr53F3pf9Zr4guY9jS5_4QAtU5y6oQmzHMKMcn1Bh45BRFjwbf9TzYUHyABUaqA9UxXwJYJkQEXFgh5lfgxZHkrhOhmA4tRnpdceV7gtF_vJpgOlXHIchDNA4SQr9oCdw0oxYubEoV_ce5gh1Jo9irfRWFRfth9T2NEGlZ6qPDcLWvt7BAXjnzLfl_jKkbPwKJid4uT3ROYxGKAnYJhkOGSp0tdgti3w5Yq1Zlqso2Aw2qQmfQtnOXNGzSwtW9mAPXhGiB8DQBKMSNgKCpoeM5BQpFJNuiFOe73LAnyUWNOJjW3YUOuT7jQt4sgq03YcSsVZSwtAhnm4nnHtFaFVgCm4DSACsAbutzFmHLDDp6coDN92mtkWNHvAJhQo1Z9aA497XbtZaFLFEbY21fxhuxBlIzNqfkzjy0lGwPHKcdxnWg29qQSBcoR7T7BVw_kT2z3ujoKlOpJioqobHq7iDA5KbJAMh_rRaEFP2M"}

But when I try to access the /api route:

curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJleHAiOjE0OTczMDYwMTgsImlhdCI6MTQ5NzMwMjQxOH0.DJjYjQSRxTDKeikHUs1Dsih7WK_7BownP3SA_gVMKCVUjfn9OfaqCp3bXFErqgAPnWtYn6u-LdX5H40ytW9m6j2pHOAAk8sR_pf_8IoWl4WedMniBzHqXs4hPqPVxH9ZJkGhDYnpWZPwHgxq6iOxnHwV_bLO3ZpLtjekOkh-B2EbWFtFbAZN5wIb-GZGLmerkWXDRzr53F3pf9Zr4guY9jS5_4QAtU5y6oQmzHMKMcn1Bh45BRFjwbf9TzYUHyABUaqA9UxXwJYJkQEXFgh5lfgxZHkrhOhmA4tRnpdceV7gtF_vJpgOlXHIchDNA4SQr9oCdw0oxYubEoV_ce5gh1Jo9irfRWFRfth9T2NEGlZ6qPDcLWvt7BAXjnzLfl_jKkbPwKJid4uT3ROYxGKAnYJhkOGSp0tdgti3w5Yq1Zlqso2Aw2qQmfQtnOXNGzSwtW9mAPXhGiB8DQBKMSNgKCpoeM5BQpFJNuiFOe73LAnyUWNOJjW3YUOuT7jQt4sgq03YcSsVZSwtAhnm4nnHtFaFVgCm4DSACsAbutzFmHLDDp6coDN92mtkWNHvAJhQo1Z9aA497XbtZaFLFEbY21fxhuxBlIzNqfkzjy0lGwPHKcdxnWg29qQSBcoR7T7BVw_kT2z3ujoKlOpJioqobHq7iDA5KbJAMh_rRaEFP2M" http://sandbox.localhost.com/api

I get:

{"code":401,"message":"JWT Token not found"}

I have the rewrite code enabled in my Apache vhost, and the token is coming through in the headers:

(Inside src/AppBundle/Security/Guard/JWTAuthenticator.php)

echo print_r(getallheaders(), true);

Array
(
    [Host] => sandbox.localhost.com
    [User-Agent] => curl/7.43.0
    [Accept] => */*
    [Authorization] => Bearer eyJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJleHAiOjE0OTczMDYwMTgsImlhdCI6MTQ5NzMwMjQxOH0.DJjYjQSRxTDKeikHUs1Dsih7WK_7BownP3SA_gVMKCVUjfn9OfaqCp3bXFErqgAPnWtYn6u-LdX5H40ytW9m6j2pHOAAk8sR_pf_8IoWl4WedMniBzHqXs4hPqPVxH9ZJkGhDYnpWZPwHgxq6iOxnHwV_bLO3ZpLtjekOkh-B2EbWFtFbAZN5wIb-GZGLmerkWXDRzr53F3pf9Zr4guY9jS5_4QAtU5y6oQmzHMKMcn1Bh45BRFjwbf9TzYUHyABUaqA9UxXwJYJkQEXFgh5lfgxZHkrhOhmA4tRnpdceV7gtF_vJpgOlXHIchDNA4SQr9oCdw0oxYubEoV_ce5gh1Jo9irfRWFRfth9T2NEGlZ6qPDcLWvt7BAXjnzLfl_jKkbPwKJid4uT3ROYxGKAnYJhkOGSp0tdgti3w5Yq1Zlqso2Aw2qQmfQtnOXNGzSwtW9mAPXhGiB8DQBKMSNgKCpoeM5BQpFJNuiFOe73LAnyUWNOJjW3YUOuT7jQt4sgq03YcSsVZSwtAhnm4nnHtFaFVgCm4DSACsAbutzFmHLDDp6coDN92mtkWNHvAJhQo1Z9aA497XbtZaFLFEbY21fxhuxBlIzNqfkzjy0lGwPHKcdxnWg29qQSBcoR7T7BVw_kT2z3ujoKlOpJioqobHq7iDA5KbJAMh_rRaEFP2M
)

Using Symfony 3.3.2 and latest JWT bundle (2.02 I believe?) Also using the stock configs in the sandbox app.

Any ideas? Thank you!

Support

Most helpful comment

As this is the first search result for "JWT not found header lexik", I'll add some infos.
If you do the same thing as @becauseinterwebs and at the last step, you cant' find the authorization line in your headers, there is probably a problem with your apache vhost config.
See the documentation part which I totally missed:

Important note for Apache users

As stated in this link and this one, Apache server will strip any Authorization header not in a valid HTTP BASIC AUTH format.

If you intend to use the authorization header mode of this bundle (and you should), please add those rules to your VirtualHost configuration :

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

NOTE: Don't put this in a Directory section, it belongs to the root of your config.

All 12 comments

Can you dump $request->headers from the authenticator to see if the Authorization header is present?

And if it is, past the content of your config.yml + security.yml here?

Here are the headers from the request object passed to the TokenExtractor:

Symfony\Component\HttpFoundation\HeaderBag Object
(
    [headers:protected] => Array
        (
            [authorization] => Array
                (
                    [0] => Bearer eyJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJleHAiOjE0OTczNjk5NjAsImlhdCI6MTQ5NzM2NjM2MH0.RMmrr3Mib9LD-kSDADSHz_I2S8OPEtN2VEE5kju3nnU1rvLynl3KEt0d_jIOByqMbP453fMKzJQp_ei1K5CM7HGXzJTqYHzLwVOI_CXO2mzhjFLmPb2uEtzbza4-B82Cfj6BBIxGCFZM7tgvK6hoaU0mP55gWwqLmS77HIeZc0ilJE5g_LwqEGyAoyEBUL7e2MB7g5zVOXarcOLXtf0s49IiewuwpBTTzU_VBYlvJR-kuDTe2AhKNYmkeJ89gSX_B8DJExKo_NNPsjkxUJBmVL4SsHV2RtLZCxroW1eQnAr-KqS-2Q41vJmDXCEG_zJw3MJnhqMhZdUqSCjbmavvoDgeTEJAtxt61DdntMov4Ihipxi-w8T4Ov7VitgV3xSORp5nZosCwLoQflhDAE_A_aflQU02_c8EovvZzWa986dsLJPUR95lFP3eeYz3FP8qpGTQUlS7wZvSeyXI9RuIBQRy-I94UMPIqdNQPpUkDpjhsjb5H-Gm15I4ecDZyqsjSUNgODecKBNITtC-fKpe7BNpCv7GJVLrrmAexRpSHSehxl-gnZcnMw_YKvaTlvnCC4YkPvtpasm76Iimwwnok6LljsRFoDoceNtp9hooq9xaCFi9IjcxaiMh4GehPh33KdhQvQdrQ1In9WIKHqtKSq5WbhbWCrnWNr6fhb1lG_M
                )

            [host] => Array
                (
                    [0] => sandbox.localhost.com
                )

            [user-agent] => Array
                (
                    [0] => curl/7.43.0
                )

            [accept] => Array
                (
                    [0] => */*
                )

            [x-php-ob-level] => Array
                (
                    [0] => 0
                )

        )

    [cacheControl:protected] => Array
        (
        )

)

security.yml

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

    providers:
        entity_provider:
            entity:
                class: AppBundle:User
                property: username

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        login:
            pattern:  ^/login
            stateless: true
            anonymous: true
            form_login:
                check_path: /login_check
                require_previous_session: false
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure

        register:
            pattern:  ^/register
            stateless: true
            anonymous: true

        api:
            pattern:  ^/api
            stateless: true
            anonymous: false
            provider: entity_provider
            guard:
                authenticators:
                    - app.jwt_token_authenticator

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

    role_hierarchy:
        ROLE_API: [ROLE_USER]

config.yml

imports:
    - { resource: parameters.yml }
    - { resource: security.yml }
    - { resource: services.yml }

# Put parameters here that don't need to change on each machine where the app is deployed
# http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
    locale: en

framework:
    #esi:             ~
    #translator:      { fallbacks: ["%locale%"] }
    secret:          "%secret%"
    router:
        resource: "%kernel.root_dir%/config/routing.yml"
        strict_requirements: ~
    form:            ~
    csrf_protection: ~
    validation:      { enable_annotations: true }
    #serializer:      { enable_annotations: true }
    templating:
        engines: ['twig']
    default_locale:  "%locale%"
    trusted_hosts:   ~
    trusted_proxies: ~
    session:
        # http://symfony.com/doc/current/reference/configuration/framework.html#handler-id
        handler_id:  session.handler.native_file
        save_path:   "%kernel.root_dir%/../var/sessions/%kernel.environment%"
    fragments:       ~
    http_method_override: true
    assets: ~

# Twig Configuration
twig:
    debug:            "%kernel.debug%"
    strict_variables: "%kernel.debug%"

# Doctrine Configuration
doctrine:
    dbal:
        driver:   pdo_mysql
        host:     "%database_host%"
        port:     "%database_port%"
        dbname:   "%database_name%"
        user:     "%database_user%"
        password: "%database_password%"
        charset:  UTF8
        # if using pdo_sqlite as your database driver:
        #   1. add the path in parameters.yml
        #     e.g. database_path: "%kernel.root_dir%/data/data.db3"
        #   2. Uncomment database_path in parameters.yml.dist
        #   3. Uncomment next line:
        #     path:     "%database_path%"

    orm:
        auto_generate_proxy_classes: "%kernel.debug%"
        naming_strategy: doctrine.orm.naming_strategy.underscore
        auto_mapping: true

# Swiftmailer Configuration
swiftmailer:
    transport: "%mailer_transport%"
    host:      "%mailer_host%"
    username:  "%mailer_user%"
    password:  "%mailer_password%"
    spool:     { type: memory }

lexik_jwt_authentication:
    private_key_path: '%jwt_private_key_path%'
    public_key_path:  '%jwt_public_key_path%'
    pass_phrase:      '%jwt_key_pass_phrase%'
    token_ttl:        '%jwt_token_ttl%'

parameters.yml

parameters:
    database_host: 127.0.0.1
    database_port: null
    database_name: lexik_jwt_auth
    database_user: root
    database_password: null
    mailer_transport: smtp
    mailer_host: 127.0.0.1
    mailer_user: null
    mailer_password: null
    secret: ThisTokenIsNotSoSecretChangeIt
    jwt_private_key_path: '%kernel.root_dir%/../var/jwt/private.pem' # ssh private key path
    jwt_public_key_path:  '%kernel.root_dir%/../var/jwt/public.pem'  # ssh public key path
    jwt_key_pass_phrase:  'foobar'                                   # ssh key pass phrase
    jwt_token_ttl:        3600

I have traced to this part of function extract(Request $request) in AuthorizationHeaderTokenExtractor.php:

if (!(count($headerParts) === 2 && $headerParts[0] === $this->prefix)) {
            return false;
}

$headerParts[0] = 'Bearer', not 'JWT' as configured in the sandbox app. Changing this call in JWTAuthenticator.php in function getTokenExtractor fixed it:

not-working:

$chainExtractor->addExtractor(new AuthorizationHeaderTokenExtractor('JWT', 'Authorization'));

working:

$chainExtractor->addExtractor(new AuthorizationHeaderTokenExtractor('Bearer', 'Authorization'));

I will close this issue. Thank you!

Ah yea... This is made to demonstrate the ability to alter token extractors from the authenticator itself, but it seems more misleading than helpful, I may change this to reflect the bundle doc. Thanks for the feedback!

As this is the first search result for "JWT not found header lexik", I'll add some infos.
If you do the same thing as @becauseinterwebs and at the last step, you cant' find the authorization line in your headers, there is probably a problem with your apache vhost config.
See the documentation part which I totally missed:

Important note for Apache users

As stated in this link and this one, Apache server will strip any Authorization header not in a valid HTTP BASIC AUTH format.

If you intend to use the authorization header mode of this bundle (and you should), please add those rules to your VirtualHost configuration :

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

NOTE: Don't put this in a Directory section, it belongs to the root of your config.

Hi @leogout , where is the virtualhost folder for the apache server of symfony ?

I got the same problem for few days now and i can't resolve it.
I still got "JWT Token not found" .
And how can you get the token in a controller for checking if the user is authenticated ?

Thanks for your reply guys.

Hi @leogout , where is the virtualhost folder for the apache server of symfony ?

Depends on your machine. On my Mac its in the direction /etc/private/apache2/
The exact file name you can find in the httpd.conf in the same directory. In my case it's a custom config file: virtualhosts-private.conf
You have then to put
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
inside
<VirtualHost *:443>

It would be great if some kind of "Notice" about this will appear in documentation for Lexik? :) I spent few hours digging what the hell is going on :)

Thanks to @leogout for this answer!

@Spomky excactly! :)
it confirms my belief that I should read the documentation more carefully

In addition to @leogout , if someone is using htaccess, can add this:

# Fix JWT Authentication problem
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
Was this page helpful?
0 / 5 - 0 ratings