Symfony - lexik jwt authentication - token not found - symfony

I am using lexik_jwt_authentication on my backend with simfony 3.3.
My problem is that the response when I try to do the login is:
{
"code": 401,
"message": "JWT Token not found"
}
Also if I navigate my site the bundle told me to provide a token in all the pages. This is OK but this should not happen when I check for the login in "login_check", and in this case I am unable to generate a token.
What am I doing wrong?
Thank you
config.yml:
lexik_jwt_authentication:
private_key_path: '%kernel.root_dir%/../var/jwt/private.pem'
public_key_path: '%kernel.root_dir%/../var/jwt/public.pem'
pass_phrase: '%jwt_key_pass_phrase%'
token_ttl: 3600
fos_user:
db_driver: orm
firewall_name: main
user_class: ApiBundle\Entity\FosUser
from_email:
address: "%mailer_user%"
sender_name: "%mailer_user%"
security.yml:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
fr3d_ldap: ~
security: false
form_login:
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
logout: true
stateless: true
anonymous: true
api:
pattern: ^/
stateless: true
provider: fos_userbundle
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
main:
pattern: ^/
fr3d_ldap: ~
form_login:
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
logout: true
stateless: true
anonymous: true

in your security.yml you need to specify into access_control that login isn't authenitcated fully like this:
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }

Related

How to Use multiple User Providers in symfony 5. How to chain it?

UPADATED CODE and PROBLEM :
I use symfony Symfony 5.3.6.
I have two kinds of users: company & candidate.
I'd like to make them able to autenticate on their side. 2 forms are coming from front end. ( but for the moment no forms).
I use lexik_jwt_authentication.jwt_token_authenticator to authenticate my both kind of users.
This is the first time I try to code for 2 providers in my security.yaml.
When I had only one , it worked. When i added company, it doesnt anymore.
Here is my updated code in my security.yaml :
security:
# https://symfony.com/doc/current/security/experimental_authenticators.html
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#c-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
App\Entity\Candidate:
algorithm: auto
App\Entity\Company:
algorithm: auto
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
app_candidate_provider:
entity:
class: App\Entity\Candidate
property: email
app_compagny_provider:
entity:
class: App\Entity\Company
property: email
app_users:
chain:
providers: ['app_candidate_provider', 'app_compagny_provider']
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
anonymous: false
json_login:
check_path: /api/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
anonymous: false
provider: app_users
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
main:
# anonymous: lazy
lazy: true
provider: app_user_provider
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: 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: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/candidates, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/api/company, roles: IS_AUTHENTICATED_FULLY }
Now, my message error is : "Not configuring explicitly the provider for the "json_login" listener on "login" firewall is ambiguous as there is more than one registered provider.."
i have followed this thread :
Not configuring explicitly the provider for the "guard" listener on "x" firewall is ambiguous as there is more than one registered provider
By remplacing
api:
pattern: ^/api/
stateless: true
anonymous: false
provider: app_users
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
with
api:
pattern: ^/api/
stateless: true
anonymous: false
provider: 'app_candidate_provider'
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
But still doesnt work
Do you have an idea where i make a mistake ?
EDIT : the final answer told by #mcsky is the good one :
security:
# https://symfony.com/doc/current/security/experimental_authenticators.html
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#c-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
App\Entity\Candidate:
algorithm: auto
App\Entity\Company:
algorithm: auto
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
app_candidate_provider:
entity:
class: App\Entity\Candidate
property: email
app_compagny_provider:
entity:
class: App\Entity\Company
property: email
app_users:
chain:
providers: ['app_candidate_provider', 'app_compagny_provider']
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
provider: app_users
anonymous: false
json_login:
check_path: /api/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
anonymous: false
provider: app_users
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
main:
# anonymous: lazy
lazy: true
provider: app_candidate_provider
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: 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: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/candidates, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/api/company, roles: IS_AUTHENTICATED_FULLY }
You can't define one user provider with multiple classes as a configuration. It is not designed to work like this. Symfony executes this class Symfony\Bridge\Doctrine\Security\User\EntityUserProvider under the wood, as you can see it work with property and email string only.
So I suggest you define two different user providers, one per class type.
So can you try this configuration?
providers:
app_candidate_provider:
entity:
class: App\Entity\Candidate
property: email
app_compagny_provider:
entity:
class: App\Entity\Company
property: email
app_users:
chain:
providers: ['app_candidate_provider', 'app_compagny_provider']
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
provider: app_users
anonymous: false
json_login:
check_path: /api/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
anonymous: false
provider: app_users
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
Let me know if something isn't clear or don't work

Change the FOS users connection property

I have a problem with the connection with the friends of symfony and jwt bundle, by default it uses the username to connect only I need to use email.
I first try to change the property in secutiy.yaml but I can't get it to work.
security:
encoders:
App\Entity\User:
algorithm: bcrypt
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:
check_path: /login_check
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:
- lexik_jwt_authentication.jwt_token_authenticator
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
Always when I try to connect it asks me for the username.
try :
fos_userbundle:
id: fos_user.user_provider.username_email

How to fix "The key _username must be a string" error with JWT

I have a website with a standard connection, and I want to add a new way to connect thanks to the API part.
I have followed this doc :
1https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Resources/doc/index.md#getting-started
So I add JWT bundle to my Symfony 3 project, and I changed my security.yml :
# app/config/security.yml
security:
encoders:
Symfony\Component\Security\Core\User\User: sha512
GS\UserBundle\Entity\User: sha512 #sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
main:
entity:
class: GS\UserBundle\Entity\User
property: login
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
anonymous: true
provider: main
stateless: true
form_login:
login_path: login
check_path: login_check
default_target_path: preLogin
logout:
path: logout
target: preLogin
remember_me:
secret: '%secret%' # se souvenir de moi
lifetime: 1000
always_remember_me: true
login:
pattern: ^/api/login
stateless: true
anonymous: true
provider: main
json_login:
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
api:
pattern: ^/api
stateless: true
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 }
I have configured my config.yml like this :
lexik_jwt_authentication:
secret_key: '%kernel.project_dir%/config/jwt/private.pem'
public_key: '%kernel.project_dir%/config/jwt/public.pem'
user_identity_field: login
pass_phrase: 'MY PASSWORD'
token_ttl: 3600
And When I tried to obtain my token with postman like this :
I have this error :
The key "_username" must be a string, "NULL" given.
So, I tried to add "user_parameter" in the security.yml in order to give the parameters name of my user entity, like this :
login:
pattern: ^/api/login
stateless: true
anonymous: true
json_login:
check_path: /api/login_check
username_parameter: login
password_parameter: mdp
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
And now Postman answer me nothing.
EDIT:
I find a commande to check my config file and I have this answer :
And if I remove the username_parameter and the password_parameter, the commande check tell me that the config is ok, but I have the same error with postman :
The key "username" must be a string, "NULL" given.
Help me please I don't find any solution...
Lexik JWT authentication config needs the provider key in the security.yaml.
login:
pattern: ^/api/login
stateless: true
anonymous: true
provider: YOUR_PRODIVER_NAME #in your case it's main
json_login:
check_path: /api/login_check
username_parameter: login
password_parameter: mdp
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
Then to be able to verify the user informations, it needs to know what field is the identity field.
So in the 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)%'
user_identity_field: YOUR_USER_FIELD # example email
token_ttl: 7200
About the request parameters, username and password have to be passed (No _)

Unable to find the controller for path "/api/login_check". The route is wrongly configured

I have a problem with "login_check" and i use Symfony 3 and LexikJWTAuthenticationBundle.
The problem :
The security.yml :
firewalls:
login:
pattern: ^/api/login
stateless: true
anonymous: true
form_login:
username_parameter: username
password_parameter: password
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
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
main:
anonymous: true
access_control:
- {path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- {path: ^/api, roles: IS_AUTHENTICATED_FULLY }
The routing.yml :
app:
resource: '#AppBundle/Controller/'
type: rest
prefix: /api
login_check:
path: api/login_check
Can you help me, please?
good day :)
Change your routing file with:
app:
resource: '#AppBundle/Controller/'
type: rest
prefix: /api
api_login_check:
path: /api/login_check

1 application with 2 login security

I have an symfony 3 application. There is one part for /api and one /back (administration)
The /api use LexikJwtAuthentication and /back FosUserBundle.
With my actual security, i have an error when i go to /back.
A Token was not found in the TokenStorage.
I think, my app try to read the Bearer token.
How can i use the FosUSerBundle security with the routes /back ?
My security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
...
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
...
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
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
guard:
authenticators:
- api.jwt_authenticator
logout: true
anonymous: true
back:
pattern: ^/back
form_login:
provider: fos_userbundle
login_path: /back/login
check_path: /back/login_check
csrf_token_generator: security.csrf.token_manager
routing.yml
fos_user_security_login:
defaults: { _controller: "FOSUserBundle:Security:login" }
path: /back/login
fos_user_security_check:
defaults: { _controller: "FOSUserBundle:Security:check" }
path: /back/login_check
fos_user_security_logout:
defaults: { _controller: "FOSUserBundle:Security:logout" }
path: /back/logout
config.yml
fos_user:
db_driver: orm
firewall_name: back
user_class: AppBundle\Entity\User
from_email:
address: "test#test.test"
sender_name: "test#test.test"
I think you forgot to add the provider and the csrf_token_generator like this (Symfony doc) :
back:
pattern: ^/back
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
login_path: /back/login
check_path: /back/login_check
And check if the FOSUser routes are behind /back routes (cf Symfony doc )

Resources