LexikJWTAuthenticationBundle icon indicating copy to clipboard operation
LexikJWTAuthenticationBundle copied to clipboard

JWTToken change fields for generate

Open shubaivan opened this issue 7 years ago • 20 comments

I use Symfony 3.3.10 with "lexik/jwt-authentication-bundle": "~2.0", and for user_identity_field I use email

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%'
user_identity_field: email

But after my user, call put request with email, I mean change email to something another. after have been change, when I call another api, example get user profile, I have error:

{
  "code": 401,
  "message": "Unable to load an user with property \"email\" = \"[email protected]\". If the user identity has changed, you must renew the token. Otherwise, verify that the \"lexik_jwt_authentication.user_identity_field\" config option is correctly set."
}

I understood, because I change email, which part for generating token, but I thought token saved in session and don't need regenerate token after change email or password.

My question how to change generating token fields, example I want use some constant field, example id?

shubaivan avatar Feb 19 '18 16:02 shubaivan

i have the same issue with two differences: user_identity_field: id

and my id of the user entity is not auto increment: /** * @ORM\Column(type="guid") * @ORM\Id * @ORM\GeneratedValue(strategy="UUID") */ private $id;

example: 9186b8bd-170b-11e8-82f8-480fcf324d89

and i use Symfony 4

saft1g avatar Feb 21 '18 13:02 saft1g

The user entity method getusername is returning the email?

bonfante avatar Feb 25 '18 22:02 bonfante

How can I change the user_identity_field username (default value) an email? I use symfony 4 and I get this error "message": "The key \"_username\" must be a string, \"NULL\" given.",. Someone found a solution?

HecFranco avatar Jun 19 '18 20:06 HecFranco

Hi @HecFranco, did you find a solution ?

alex74m avatar Jul 20 '18 11:07 alex74m

@HecFranco that's for the form_login part which is a symfony thing, not related to this bundle. What you need is:

form_login:
    # ...
    username_parameter: email

chalasr avatar Jul 20 '18 11:07 chalasr

Well, the error is

The key "email" must be a string, "NULL" given.

alex74m avatar Jul 20 '18 12:07 alex74m

Then your HTTP request is incorrect, it just does not contain the email parameter.

chalasr avatar Jul 20 '18 12:07 chalasr

Again, that's a symfony issue, form_login is part of symfony. You're looking for https://symfony.com/support

chalasr avatar Jul 20 '18 12:07 chalasr

I use Symfony 3.3.11 with "lexik/jwt-authentication-bundle": "2.4.4", and user_identity_field - mobileNo

I get this error on consuming login API

eerror": { "code": 400, "message": "Bad Request", "exception": [ { "message": "The key "username" must be provided.", ...... } ] }

RajeshwariN avatar Sep 20 '19 04:09 RajeshwariN

I use Symfony 3.3.11 with "lexik/jwt-authentication-bundle": "2.4.4", and user_identity_field - mobileNo

I get this error on consuming login API

eerror": { "code": 400, "message": "Bad Request", "exception": [ { "message": "The key "username" must be provided.", ...... } ] }

The answer to your problem is right there. If you are not using the key 'username' for authentication, you must specify it. For example, if you are using 'mobileNo' for authentication, you must specify it in your security.yaml.

form_login:
    # ...
    username_parameter: mobileNo

EresDev avatar Sep 20 '19 10:09 EresDev

@EresDev thanks for help! I updated user_identity_field in config.yml and it worked

RajeshwariN avatar Sep 20 '19 15:09 RajeshwariN

login: # json_login: # username_path: email

saifgo avatar Apr 10 '20 10:04 saifgo

Hello :)) Have I misunderstood something? I want to use the field "email" to get the token at the endpoint "check_login". I have exactly the same problem as @RajeshwariN and have tried the solution of @EresDev. Or the one from @saifgo because I use json_login. But it doesn't work. "message": "The key "username" must be provided.".. I have change the following parts in the security.yaml

 providers:
        entity_provider:
            entity:
                class: App\Entity\User
                property: email

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

and into lexik_jwt_authentication.yaml

lexik_jwt_authentication:
    secret_key:       '%kernel.project_dir%/config/jwt/private.pem' # required for token creation
    public_key:       '%kernel.project_dir%/config/jwt/public.pem'  # required for token verification
    pass_phrase:      '' # required for token creation, usage of an environment variable is recommended
    token_ttl:        3600
    user_identity_field: email

HashtagAssist avatar Jan 14 '21 16:01 HashtagAssist

@HashtagAssist Try by adding provider: entity_provider under login

RajeshwariN avatar Jan 14 '21 17:01 RajeshwariN

Thanks for the quick response! Anyway that dont help :( i still get the the token by this json {"username":"test","password":"test"}. {"username":"[email protected]","password":"test"} return "Invalid credentials" . And {"email":"[email protected]","password":"test"} result in a 400 (The key "username" must be provided.)

HashtagAssist avatar Jan 14 '21 17:01 HashtagAssist

I have the same issue, while I am trying to redirect to login api route, but it gives me The key "password" must be provided. My controller returns a redirect response:

return $this->redirectToRoute('api_login', [
    'email'    => $user->getEmail(),
    'password' => $user->getPassword(),
], Response::HTTP_TEMPORARY_REDIRECT);

My security.yaml is configured with the following code:

security:
    role_hierarchy:
        ROLE_ADMIN:         [ROLE_USER, ROLE_SONATA_ADMIN]
        ROLE_SUPER_ADMIN:   [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    encoders:
        FOS\UserBundle\Model\UserInterface: sha512

    providers:
        fos_userbundle:
            id: fos_user.user_provider.username_email
        json_provider:
            entity:
                class: 'App\Entity\Security\User'
                property: 'id'


    firewalls:
        # Disabling the security for the web debug toolbar, the profiler and Assetic.
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false

        refresh:
            pattern: ^/api/auth/token/refresh
            stateless: true
            anonymous: true

        api_registration:
            pattern: ^/api/auth/register
            stateless: true
            anonymous: true

        api_send_reset_email:
            pattern: ^/api/auth/reset/send-email
            stateless: true
            anonymous: true

        api_reset_password:
            pattern: ^/api/auth/reset/reset-password
            stateless: true
            anonymous: true

        api_login:
            pattern: ^/api/auth/login
            stateless: true
            anonymous: true
            provider: fos_userbundle
            json_login:
                check_path: /api/auth/login
                username_path: email
                password_path: password
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure

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

        admin:
            pattern:            /admin(.*)
            context:            user
            form_login:
                provider:       fos_userbundle
                login_path:     sonata_user_admin_security_login
                use_forward:    true
                check_path:     sonata_user_admin_security_check
                failure_path:   null

            logout:
                path:           sonata_user_admin_security_logout

            remember_me:
                secret:      '%env(APP_SECRET)%'
                path:       /
                lifetime:   2592000 # 1 month in seconds

            anonymous:          true

        main:
            pattern: .*
            context: user
            anonymous: true
            logout: true

        default:
            anonymous: ~

    access_control:
#        # URL of FOSUserBundle which need to be available to anonymous users
        - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }

        # Admin login page needs to be access without credential
        - { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY }

        # Secured part of the site
        # This config requires being logged for the whole site and having the admin role for the admin part.
        # Change these rules to adapt them to your needs
        - { path: ^/eloquent-media/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
        - { path: ^/admin/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
        - { path: ^/api/auth, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }

    access_decision_manager:
        strategy: unanimous

And lexik_jwt_authentication.yaml:

lexik_jwt_authentication:
    secret_key:          '%env(resolve:JWT_SECRET_KEY)%'
    public_key:          '%env(resolve:JWT_PUBLIC_KEY)%'
    pass_phrase:         '%env(JWT_PASSPHRASE)%'
    token_ttl:           86400
    user_identity_field: id

Any suggestions?

gettmure avatar Jan 26 '21 09:01 gettmure

I have the same issue, while I am trying to redirect to login api route, but it gives me The key "password" must be provided. My controller returns a redirect response:

return $this->redirectToRoute('api_login', [
    'email'    => $user->getEmail(),
    'password' => $user->getPassword(),
], Response::HTTP_TEMPORARY_REDIRECT);

My security.yaml is configured with the following code:

security:
    role_hierarchy:
        ROLE_ADMIN:         [ROLE_USER, ROLE_SONATA_ADMIN]
        ROLE_SUPER_ADMIN:   [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    encoders:
        FOS\UserBundle\Model\UserInterface: sha512

    providers:
        fos_userbundle:
            id: fos_user.user_provider.username_email
        json_provider:
            entity:
                class: 'App\Entity\Security\User'
                property: 'id'


    firewalls:
        # Disabling the security for the web debug toolbar, the profiler and Assetic.
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false

        refresh:
            pattern: ^/api/auth/token/refresh
            stateless: true
            anonymous: true

        api_registration:
            pattern: ^/api/auth/register
            stateless: true
            anonymous: true

        api_send_reset_email:
            pattern: ^/api/auth/reset/send-email
            stateless: true
            anonymous: true

        api_reset_password:
            pattern: ^/api/auth/reset/reset-password
            stateless: true
            anonymous: true

        api_login:
            pattern: ^/api/auth/login
            stateless: true
            anonymous: true
            provider: fos_userbundle
            json_login:
                check_path: /api/auth/login
                username_path: email
                password_path: password
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure

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

        admin:
            pattern:            /admin(.*)
            context:            user
            form_login:
                provider:       fos_userbundle
                login_path:     sonata_user_admin_security_login
                use_forward:    true
                check_path:     sonata_user_admin_security_check
                failure_path:   null

            logout:
                path:           sonata_user_admin_security_logout

            remember_me:
                secret:      '%env(APP_SECRET)%'
                path:       /
                lifetime:   2592000 # 1 month in seconds

            anonymous:          true

        main:
            pattern: .*
            context: user
            anonymous: true
            logout: true

        default:
            anonymous: ~

    access_control:
#        # URL of FOSUserBundle which need to be available to anonymous users
        - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }

        # Admin login page needs to be access without credential
        - { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY }

        # Secured part of the site
        # This config requires being logged for the whole site and having the admin role for the admin part.
        # Change these rules to adapt them to your needs
        - { path: ^/eloquent-media/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
        - { path: ^/admin/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
        - { path: ^/api/auth, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }

    access_decision_manager:
        strategy: unanimous

And lexik_jwt_authentication.yaml:

lexik_jwt_authentication:
    secret_key:          '%env(resolve:JWT_SECRET_KEY)%'
    public_key:          '%env(resolve:JWT_PUBLIC_KEY)%'
    pass_phrase:         '%env(JWT_PASSPHRASE)%'
    token_ttl:           86400
    user_identity_field: id

Any suggestions?

I assume you would have used this class use Symfony\Component\HttpFoundation\Request; to handle the requests. In symfony 5.2, somehow this class is not retrieving the post payloads. Instead use this class use SymfonyBundles\JsonRequestBundle\JsonRequestBundle; after installing it using composer require symfony-bundles/json-request-bundle command.

priyankatotala avatar May 06 '21 03:05 priyankatotala

I have the same issue, while I am trying to redirect to login api route, but it gives me The key "password" must be provided. My controller returns a redirect response:

return $this->redirectToRoute('api_login', [
    'email'    => $user->getEmail(),
    'password' => $user->getPassword(),
], Response::HTTP_TEMPORARY_REDIRECT);

My security.yaml is configured with the following code:

security:
    role_hierarchy:
        ROLE_ADMIN:         [ROLE_USER, ROLE_SONATA_ADMIN]
        ROLE_SUPER_ADMIN:   [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    encoders:
        FOS\UserBundle\Model\UserInterface: sha512

    providers:
        fos_userbundle:
            id: fos_user.user_provider.username_email
        json_provider:
            entity:
                class: 'App\Entity\Security\User'
                property: 'id'


    firewalls:
        # Disabling the security for the web debug toolbar, the profiler and Assetic.
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false

        refresh:
            pattern: ^/api/auth/token/refresh
            stateless: true
            anonymous: true

        api_registration:
            pattern: ^/api/auth/register
            stateless: true
            anonymous: true

        api_send_reset_email:
            pattern: ^/api/auth/reset/send-email
            stateless: true
            anonymous: true

        api_reset_password:
            pattern: ^/api/auth/reset/reset-password
            stateless: true
            anonymous: true

        api_login:
            pattern: ^/api/auth/login
            stateless: true
            anonymous: true
            provider: fos_userbundle
            json_login:
                check_path: /api/auth/login
                username_path: email
                password_path: password
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure

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

        admin:
            pattern:            /admin(.*)
            context:            user
            form_login:
                provider:       fos_userbundle
                login_path:     sonata_user_admin_security_login
                use_forward:    true
                check_path:     sonata_user_admin_security_check
                failure_path:   null

            logout:
                path:           sonata_user_admin_security_logout

            remember_me:
                secret:      '%env(APP_SECRET)%'
                path:       /
                lifetime:   2592000 # 1 month in seconds

            anonymous:          true

        main:
            pattern: .*
            context: user
            anonymous: true
            logout: true

        default:
            anonymous: ~

    access_control:
#        # URL of FOSUserBundle which need to be available to anonymous users
        - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }

        # Admin login page needs to be access without credential
        - { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY }

        # Secured part of the site
        # This config requires being logged for the whole site and having the admin role for the admin part.
        # Change these rules to adapt them to your needs
        - { path: ^/eloquent-media/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
        - { path: ^/admin/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
        - { path: ^/api/auth, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/api, roles: IS_AUTHENTICATED_FULLY }

    access_decision_manager:
        strategy: unanimous

And lexik_jwt_authentication.yaml:

lexik_jwt_authentication:
    secret_key:          '%env(resolve:JWT_SECRET_KEY)%'
    public_key:          '%env(resolve:JWT_PUBLIC_KEY)%'
    pass_phrase:         '%env(JWT_PASSPHRASE)%'
    token_ttl:           86400
    user_identity_field: id

Any suggestions?

I assume you would have used this class use Symfony\Component\HttpFoundation\Request; to handle the requests. In symfony 5.2, somehow this class is not retrieving the post payloads. Instead use this class use SymfonyBundles\JsonRequestBundle\JsonRequestBundle; after installing it using composer require symfony-bundles/json-request-bundle command.

I've already figured out, that trouble is in 307 response. It just does not support this behaviour. It can pass only those parameters, which are in the request. In this situation it would work, if I will pass email and password fields in the request body.

But thank you for the reply! :3

gettmure avatar May 06 '21 08:05 gettmure

The user entity method getusername is returning the email?

Thank U very much! This solved for me... I had changed the login field to phone number, but (my mistake, I know) I forgot to change that info on User::getUsername() method at my entity class!!

eciosilva avatar Oct 31 '21 04:10 eciosilva

Hello :)) Have I misunderstood something? I want to use the field "email" to get the token at the endpoint "check_login". I have exactly the same problem as @RajeshwariN and have tried the solution of @EresDev. Or the one from @saifgo because I use json_login. But it doesn't work. "message": "The key "username" must be provided.".. I have change the following parts in the security.yaml

 providers:
        entity_provider:
            entity:
                class: App\Entity\User
                property: email
  firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        login:
            pattern:  ^/login
            stateless: true
            anonymous: true
            json_login:
                username_path: email
                check_path: /login_check
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure

and into lexik_jwt_authentication.yaml

lexik_jwt_authentication:
    secret_key:       '%kernel.project_dir%/config/jwt/private.pem' # required for token creation
    public_key:       '%kernel.project_dir%/config/jwt/public.pem'  # required for token verification
    pass_phrase:      '' # required for token creation, usage of an environment variable is recommended
    token_ttl:        3600
    user_identity_field: email

it works properly

ujikstark avatar Jan 01 '22 08:01 ujikstark