401 JWT Token not found

20,203

Solution 1

Problem be is encrypted private key.

Private key is normally encrypted and protected with a passphrase or password before the private key is transmitted or sent. When you receive an encrypted private key, you must decrypt the private key in order to use the private key.

To identify whether a private key is encrypted or not, open the private key in any text editor. An encrypted key has the first few lines that similar to the following, with the ENCRYPTED word:

---BEGIN RSA PRIVATE KEY---
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,AB8E2B5B2D989271273F6730B6F9C687
------
------
------
---END RSA PRIVATE KEY---

On the other hand, an unecrypted key will have the following format:

---BEGIN RSA PRIVATE KEY---
------
------
------
---END RSA PRIVATE KEY---

Encrypted key cannot be used directly in applications in most scenario. It must be decrypted first.

OpenSSL in Linux is the easiest way to decrypt an encrypted private key. Use the following command to decrypt an encrypted RSA key:

openssl rsa -in ssl.key.secure -out ssl.key

Make sure to replace the “server.key.secure” with the filename of your encrypted key, and “server.key” with the file name that you want for your encrypted output key file.

If the encrypted key is protected by a passphrase or password, enter the pass phrase when prompted.

Once done, you will notice that the ENCRYPTED wording in the file has gone.

If be I did not use Postman, then I would not have seen the error of Symfony, which helped me find the root of the problem. It would be nice if be Lesik LexikJWTAuthenticationBundle processed this error.

Solution 2

My solutions was to add this in .htaccess

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

Solution 3

You need to allow Authorization header either in your project .htaccess file or virtual site configurations (example /etc/apache2/sites-available/000-default.conf)

<Directory your_project_directory>
            Options Indexes FollowSymLinks MultiViews
            AllowOverride None
            Order allow,deny
            Allow from all
            Require all granted
            RewriteEngine on
            RewriteCond %{HTTP:Authorization} ^(.*)
            RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
    </Directory>

Solution 4

To fix the issue, I added following line in my Apache configuration file.

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

You can find the details in github LexikJWTAuthenticationBundle bottom of the page.

Solution 5

It works for me using this solution

RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
Share:
20,203
Dmitry S.
Author by

Dmitry S.

I'm Front-end Developer full-featured web and mobile apps. My main programming experience is with JavaScript (Node.js), including HTML, SVG, CSS as techs for build UX/UI. Interested in a challenging technical track career in a software development that works for the good of mankind. Love pure UI and clearly UX. Main stack: React, Redux (Rematch), Next.js, Tailwind CSS, Express.js, PouchDB Observation: React Native, TWA (Trusted Web Activity), PWA Systems Design: RESTful API, GraphQL, Microservices Profiles GitHub: https://github.com/reducio StackOverflow: https://stackoverflow.com/users/8845218/dmitry-s HabrCareer: https://career.habr.com/stavanger UX/UI Tools: Figma, Sketch, Zeplin, Framer Frontend Experience Web APIs: DOM, Fetch API, History API, Service Worker API, Web Workers API, HTML Drag and Drop API, Intersection Observer API, Canvas API, WebGL, etc Frameworks/Libs: React, Redux, Rematch, Next.js, Tailwind CSS, PouchDB, etc UI components: Ant Design, Material UI, Tailwind UI Linters/Formatters: ESLint, Prettier Types: TypeScript Tools: Webpack, Rollup, Parcel Package Manager: NPM, Yarn Backend, DevOps Experience Frameworks/Libs: Express.js Protocols/Standarts: RFCs IETF (HTTP, HTTP2), WebSocket, GraphQL Web Servers: Nginx NoSQL Databases: MongoDB, CouchDB Message Brokers/Caching: RabbitMQ, Redis (applied use) Process Managers: PM2 Containers: Docker

Updated on July 17, 2022

Comments

  • Dmitry S.
    Dmitry S. almost 2 years

    I provided two versions of the security.yaml file. The second version according to API Platform documentation. API Platform sends to the creation a custom user provider. For the second option security.yaml recommended at API Platform docs, I need to create two additional files. I did not attach them to the topic, but will do it if necessary.

    But I think that problem it is in JWT.

    Environment:

    • node v8.9.4
    • chrome 64.0.3282.119
    • Ubuntu 16.04
    • axios version: 0.16.2
    • Vue.js 2.4.2
    • vue-axios 2.0.2
    • api-platform/api-pack: 1.0
    • Symfony 4.0.4

    User.php

    <?php
    
    namespace App\Entity;
    
    use Doctrine\ORM\Mapping as ORM;
    use Symfony\Component\Security\Core\User\UserInterface;
    
    /**
     * @ORM\Table(name="app_users")
     * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
     */
    class User implements UserInterface, \Serializable
    {
        /**
         * @ORM\Column(type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;
    
        /**
         * @ORM\Column(type="string", length=25, unique=true)
         */
        private $username;
    
        /**
         * @ORM\Column(type="string", length=64)
         */
        private $password;
    
        /**
         * @ORM\Column(type="string", length=60, unique=true)
         */
        private $email;
    
        /**
         * @ORM\Column(name="is_active", type="boolean")
         */
        private $isActive;
    
        public function __construct() // add $username
        {
            $this->isActive = true;
        }
    
        public function getUsername()
        {
            return $this->username;
        }
    
        public function getSalt()
        {
            // you *may* need a real salt depending on your encoder
            // see section on salt below
            return null;
        }
    
        public function getPassword()
        {
            return $this->password;
        }
    
        public function getRoles()
        {
            return array('ROLE_ADMIN');
        }
    
        public function eraseCredentials()
        {
        }
    
        /** @see \Serializable::serialize() */
        public function serialize()
        {
            return serialize(array(
                $this->id,
                $this->username,
                $this->password,
                // see section on salt below
                // $this->salt,
            ));
        }
    
        /** @see \Serializable::unserialize() */
        public function unserialize($serialized)
        {
            list (
                $this->id,
                $this->username,
                $this->password,
                // see section on salt below
                // $this->salt
            ) = unserialize($serialized);
        }
    }
    

    First option security.yaml

    security:
    
        encoders:
            App\Entity\User:
                algorithm: bcrypt
    
        providers:
    
            our_db_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
                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
                provider: our_db_provider
                guard:
                    authenticators:
                        - lexik_jwt_authentication.jwt_token_authenticator
    
        access_control:
            - { path: ^/admin, roles: ROLE_ADMIN }
            - { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
            - { path: ^/api,       roles: IS_AUTHENTICATED_FULLY }
    

    Second option security.yaml

    security:
    
        encoders:
            App\Entity\User:
                algorithm: bcrypt
    
            App\Security\User\WebserviceUser: bcrypt
    
        providers:
    
            our_db_provider:
                entity:
                    class: App\Entity\User
                    property: username
    
            webservice:
                id: App\Security\User\WebserviceUserProvider
    
        firewalls:
            dev:
                pattern: ^/(_(profiler|wdt)|css|images|js)/
                security: false
    
            login:
                pattern:  ^/api/login
                stateless: true
                anonymous: true
                provider: webservice
                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
                provider: our_db_provider
                guard:
                    authenticators:
                        - lexik_jwt_authentication.jwt_token_authenticator
        access_control:
            - { path: ^/admin, roles: ROLE_ADMIN }
            - { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
            - { path: ^/api,       roles: IS_AUTHENTICATED_FULLY }
    

    Headers

    headers

    curl

    curl

    curl with headers

    curl with headers

    In browser

    in browser

    .env

    ###> lexik/jwt-authentication-bundle ###
    # Key paths should be relative to the project directory 
    JWT_PRIVATE_KEY_PATH=var/jwt/private.pem
    JWT_PUBLIC_KEY_PATH=var/jwt/public.pem
    JWT_PASSPHRASE=d70414362252a41ce772dff4823d084d
    ###< lexik/jwt-authentication-bundle ###
    

    lexik_jwt_authentication.yaml

    lexik_jwt_authentication:
        private_key_path: '%kernel.project_dir%/%env(JWT_PRIVATE_KEY_PATH)%'
        public_key_path:  '%kernel.project_dir%/%env(JWT_PUBLIC_KEY_PATH)%'
        pass_phrase:      '%env(JWT_PASSPHRASE)%'
    
  • Dmitry S.
    Dmitry S. about 6 years
    Thanks for answer. I fulfilled all these steps, it is clear from the topic, but I get via curl {"code":401,"message":"Bad credentials"}. Also it is seen in review Headers that I get correct headers.
  • habibun
    habibun about 6 years
    then check your provider: webservice carefully
  • Dmitry S.
    Dmitry S. about 6 years
    The same provider works with the login form for the dashboard correctly: github.com/krypton-code/hastore-shop/blob/master/src/Entity/‌​…
  • habibun
    habibun about 6 years
  • Dmitry S.
    Dmitry S. about 6 years
    I use nginx or you refer to on 'A stateless form_login replacement' or 'Impersonation'?
  • Dmitry S.
    Dmitry S. about 6 years
    Thanks for answer, but I tried already use these variants. The second option is not like as solution for me, need use our_db_provider. I want to understand the root of the problem.
  • Zotov Egor
    Zotov Egor about 6 years
    If you wanna login with jwt you have to use json_login instead of form_login. Did you try to set your custom provider in login firewall rule?
  • Dmitry S.
    Dmitry S. about 6 years
    Yes, I needed our_db_provider
  • Dmitry S.
    Dmitry S. about 6 years
    Update issue on github, last comment: github.com/api-platform/api-platform/issues/557
  • Jorr.it
    Jorr.it over 5 years
  • TaouBen
    TaouBen almost 5 years
    I have the same problem, but the code you added is included now by default in new version, so I don't think your solution is the answer to the 401 error.
  • TaouBen
    TaouBen almost 5 years
    I did not understand what to do exactly, I am suffering.
  • TaouBen
    TaouBen almost 5 years
    I am not on linux, but windows