1

I want to use jwt token in my symfony project. But i have a problem because when i use: curl.exe -X POST -H "Content-Type: application/json" http://localhost:81/api/login_check -d '{"username": "f.djawid@outlook.com","password":"000000"}'

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

This is my security.yml:

#/config/packages/security.yml

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: email
        # used to reload user from session & other features (e.g. switch_user)
        # used to reload user from session & other features (e.g. switch_user)
        # used to reload user from session & other features (e.g. switch_user)
    firewalls:  
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        api:
            pattern: ^/api
            stateless: true
            guard:
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator
        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            
            
        main:
            anonymous: true
                

    # 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/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/api/login,       roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/api,       roles: IS_AUTHENTICATED_FULLY }

As you can see i use the lexikJWTAthenticationBundle. I made a private key and public key with ssl.

I use docker to run the apache server where my localhost is running. This is my vhost config:

#/.docker/config/sf4.conf

<VirtualHost *:80>

        Define server_name sf4.local
        Define basedocroot  /home/wwwroot/sf4
        Define docrootweb   ${basedocroot}/public
        Define logdir   /var/log/apache2/

        <FilesMatch .php$>
         SetHandler "proxy:fcgi://sf4_php:9000"
        </FilesMatch>

        ServerName ${server_name}
        DocumentRoot ${docrootweb}
        ErrorLog ${logdir}/error.log
        CustomLog ${logdir}/access.log Combined

        RewriteEngine On
        RewriteCond %{HTTP:Authorization} ^(.*)
        RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

        <Directory ${docrootweb}>
            AllowOverride All
            Require all granted
        </Directory>

        <Directory ${basedocroot}/var>
            <IfModule mod_authz_core.c>
                Require all denied
            </IfModule>
            <IfModule !mod_authz_core.c>
                Order deny,allow
                Deny from all
            </IfModule>
        </Directory>

        <Directory ${docrootweb}>
            DirectoryIndex ${docrootweb}/index.php
            <IfModule mod_negotiation.c>
                Options -MultiViews
            </IfModule>

            <IfModule mod_rewrite.c>
                RewriteEngine On
                RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
                RewriteRule ^(.*) - [E=BASE:%1]

                RewriteCond %{HTTP:Authorization} .
                RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

                RewriteCond %{ENV:REDIRECT_STATUS} ^$
                RewriteRule ^index\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L]

                RewriteCond %{REQUEST_FILENAME} -f
                RewriteRule ^ - [L]

                RewriteRule ^ %{ENV:BASE}/index.php [L]
            </IfModule>

            <IfModule !mod_rewrite.c>
                <IfModule mod_alias.c>
                    RedirectMatch 302 ^/$ /index.php/
                </IfModule>
            </IfModule>
        </Directory>

        Undefine server_name
        Undefine basedocroot
        Undefine docrootweb
        Undefine logdir
</VirtualHost>


I found on another post that the solution might be that i have to add the Rewrite for Autherization if i use Apache but its already added there and its still not posting the jwt token when used curl like i did above.

I also made user entity with make:user and i added the username, roles and password values in the table user. In the curl you can see that i use 000000 as the password. In the database this password is hashed with argon2i.

I really don't know why i can't see the jwt token. I have looked everywhere in the internet, but nothing seems to work for me.

EDIT

I also have this in the lexik_jwt_authentication.yml:

#/config/packages/lexik_jwt_authentication.yml

lexik_jwt_authentication:
    secret_key: '%env(resolve:JWT_SECRET_KEY)%'
    public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
    pass_phrase: '%env(JWT_PASSPHRASE)%'

And this is what i defined in my .env file:

# /.env
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=accountingmodule

Also when in the security.yml when i swap the login and api headers i get this error:

{"type":"https:\/\/tools.ietf.org\/html\/rfc2616#section-10","title":"An error occurred","status":400,"detail":"Invalid JSON.","class":"Symfony\\Component\\HttpKernel\\Exception\\BadRequestHttpException","trace":[{"namespace":"","short_class":"","class":"","type":"","function":"","file":"\/home\/wwwroot\/sf4\/vendor\/symfony\/security-http\/Firewall\/UsernamePasswordJsonAuthenticationListener.php","line":108,"args":[]},{"namespace":"Symfony\\Component\\Security\\Http\\Firewall","short_class":"UsernamePasswordJsonAuthenticationListener","class":"Symfony\\Component\\Security\\Http\\Firewall\\UsernamePasswordJsonAuthenticationListener","type":"->","function":"authenticate","file":"\/home\/wwwroot\/sf4\/vendor\/symfony\/security-bundle\/Debug\/WrappedLazyListener.php","line":49,"args":[["object","Symfony\\Component\\HttpKernel\\Event\\RequestEvent"]]},{"namespace":"Symfony\\Bundle\\SecurityBundle\\Debug","short_class":"WrappedLazyListener","class":"Symfony\\Bundle\\SecurityBundle\\Debug\\WrappedLazyListener","type":"->","function":"authenticate","file":"\/home\/wwwroot\/sf4\/vendor\/symfony\/security-http\/Firewall\/AbstractListener.php","line":27,"args":[["object","Symfony\\Component\\HttpKernel\\Event\\RequestEvent"]]},{"namespace":"Symfony\\Component\\Security\\Http\\Firewall","short_class":"AbstractListener","class":"Symfony\\Component\\Security\\Http\\Firewall\\AbstractListener","type":"->","function":"__invoke","file":"\/home\/wwwroot\/sf4\/vendor\/symfony\/security-bundle\/Debug\/TraceableFirewallListener.php","line":62,"args":[["object","Symfony\\Component\\HttpKernel\\Event\\RequestEvent"]]},{"namespace":"Symfony\\Bundle\\SecurityBundle\\Debug","short_class":"TraceableFirewallListener","class":"Symfony\\Bundle\\SecurityBundle\\Debug\\TraceableFirewallListener","type":"->","function":"callListeners","file":"\/home\/wwwroot\/sf4\/vendor\/symfony\/security-http\/Firewall.php","line":98,"args":[["object","Symfony\\Component\\HttpKernel\\Event\\RequestEvent"],["object","Generator"]]},{"namespace":"Symfony\\Component\\Security\\Http","short_class":"Firewall","class":"Symfony\\Component\\Security\\Http\\Firewall","type":"->","function":"onKernelRequest","file":"\/home\/wwwroot\/sf4\/vendor\/symfony\/event-dispatcher\/Debug\/WrappedListener.php","line":126,"args":[["object","Symfony\\Component\\HttpKernel\\Event\\RequestEvent"],["string","kernel.request"],["object","Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher"]]},{"namespace":"Symfony\\Component\\EventDispatcher\\Debug","short_class":"WrappedListener","class":"Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener","type":"->","function":"__invoke","file":"\/home\/wwwroot\/sf4\/vendor\/symfony\/event-dispatcher\/EventDispatcher.php","line":264,"args":[["object","Symfony\\Component\\HttpKernel\\Event\\RequestEvent"],["string","kernel.request"],["object","Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher"]]},{"namespace":"Symfony\\Component\\EventDispatcher","short_class":"EventDispatcher","class":"Symfony\\Component\\EventDispatcher\\EventDispatcher","type":"->","function":"doDispatch","file":"\/home\/wwwroot\/sf4\/vendor\/symfony\/event-dispatcher\/EventDispatcher.php","line":239,"args":[["array",[["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"]]],["string","kernel.request"],["object","Symfony\\Component\\HttpKernel\\Event\\RequestEvent"]]},{"namespace":"Symfony\\Component\\EventDispatcher","short_class":"EventDispatcher","class":"Symfony\\Component\\EventDispatcher\\EventDispatcher","type":"->","function":"callListeners","file":"\/home\/wwwroot\/sf4\/vendor\/symfony\/event-dispatcher\/EventDispatcher.php","line":73,"args":[["array",[["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"],["object","Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener"]]],["string","kernel.request"],["object","Symfony\\Component\\HttpKernel\\Event\\RequestEvent"]]},{"namespace":"Symfony\\Component\\EventDispatcher","short_class":"EventDispatcher","class":"Symfony\\Component\\EventDispatcher\\EventDispatcher","type":"->","function":"dispatch","file":"\/home\/wwwroot\/sf4\/vendor\/symfony\/event-dispatcher\/Debug\/TraceableEventDispatcher.php","line":168,"args":[["object","Symfony\\Component\\HttpKernel\\Event\\RequestEvent"],["string","kernel.request"]]},{"namespace":"Symfony\\Component\\EventDispatcher\\Debug","short_class":"TraceableEventDispatcher","class":"Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher","type":"->","function":"dispatch","file":"\/home\/wwwroot\/sf4\/vendor\/symfony\/http-kernel\/HttpKernel.php","line":134,"args":[["object","Symfony\\Component\\HttpKernel\\Event\\RequestEvent"],["string","kernel.request"]]},{"namespace":"Symfony\\Component\\HttpKernel","short_class":"HttpKernel","class":"Symfony\\Component\\HttpKernel\\HttpKernel","type":"->","function":"handleRaw","file":"\/home\/wwwroot\/sf4\/vendor\/symfony\/http-kernel\/HttpKernel.php","line":80,"args":[["object","Symfony\\Component\\HttpFoundation\\Request"],["integer",1]]},{"namespace":"Symfony\\Component\\HttpKernel","short_class":"HttpKernel","class":"Symfony\\Component\\HttpKernel\\HttpKernel","type":"->","function":"handle","file":"\/home\/wwwroot\/sf4\/vendor\/symfony\/http-kernel\/Kernel.php","line":201,"args":[["object","Symfony\\Component\\HttpFoundation\\Request"],["integer",1],["boolean",true]]},{"namespace":"Symfony\\Component\\HttpKernel","short_class":"Kernel","class":"Symfony\\Component\\HttpKernel\\Kernel","type":"->","function":"handle","file":"\/home\/wwwroot\/sf4\/public\/index.php","line":25,"args":[["object","Symfony\\Component\\HttpFoundation\\Request"]]}]}

3 Answers3

0

On Windows, things are always different...

The single quotes do not work for the data. You have to use double quotes and escape the ones in your data by using \" or """.

curl.exe -X POST -H "Content-Type: application/json" http://localhost:81/api/login_check -d "{\"username\":\"f.djawid@outlook.com\",\"password\":\"000000\"}"

For information: How do I POST JSON data with cURL? (accepted answer and comments)

Spomky-Labs
  • 15,473
  • 5
  • 40
  • 64
0

So i just solved the problem. The problem was that i had to switch the position of login header and api header in security.yml. This time i used postman to test if it works and i get a token back. The reason why it's still not working in my local server is because for some reason the symfony kernel isn't giving any response, but that is entirly another problem.

  • I have mine at the top in the access_control area and the JWT token works great. Is this what you did? - { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } – Robert Saylor May 11 '21 at 11:38
  • my login firewall rule is also before api firewall rule. IE: in firewalls I have dev, login, api, main. The order of the firewall rules are also important. – Robert Saylor May 11 '21 at 11:40
  • It was confusing for me but now it's clear why login has to be first and then the api header –  May 12 '21 at 19:20
-1

curl -H 'Accept: application/json' -H "Authorization: Bearer AAAATOKENBBBBB" https://hostname/api/myresource

You use the following curl:

curl.exe -X POST -H "Content-Type: application/json" http://localhost:81/api/login_check -d '{"username": "f.djawid@outlook.com","password":"000000"}'

This looks like a Login request.

There are 2 types of requests to an API regarding Authentication:

  1. Authenticated requests
  2. Public requests.

The Authenticated requests need a JWT token in the header: {'Authorization': 'Bearer token'} and your API-side should check for that, and give an error back if no JWT is given.

The Public requests should not check on JWT in the API. There are a few Public Requests in the Authorization section:

  • /auth/login
  • /auth/forgotpassword
  • /auth/signin

Examples of Authenticated requests in the Auth section:

  • /auth/profile (change the profile)

Looking at the endpoint you are calling: /api/login_check Where is it specified that this is an unauthenticated request? Not knowing Symfony, but I see: {path: ^/api} The /api/login_check matches according to standard regex rules.

Hope to have helped you further.

Stephan Vierkant
  • 9,674
  • 8
  • 61
  • 97
BertC
  • 2,243
  • 26
  • 33
  • Do you mean with unauthenticated request the acces control? There i have specified that only ^/api needs authentication(IS_AUTHENTICATED_FULLY) and the path /api/login_check uses login which is unauthenticated(IS_AUTHENTICATED_ANONYMOUSLY). –  May 10 '21 at 11:11
  • Are you sure the second path (^/api/login) is matched? – BertC May 10 '21 at 11:34
  • I am following everything that is said in post: https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Resources/doc/index.md#getting-started –  May 10 '21 at 19:47
  • Please i really need help with this problem –  May 10 '21 at 19:47
  • Hello @Fardin03, I still think the problem is fairly simple: Are you sure that your /api/login_check is matched against a IS_AUTHENTICATED_ANONYMOUSLY path? Standard Regex rules would imply that is does ( ^/api/login ). But I would double check that. For example put the ^/api/login_check in the paths. – BertC May 11 '21 at 07:50