In my Symfony (3.4.24) project with FOSUserBundle (2.0.2) I installed LexikJWTAuthenticationBundle (2.6.3).
I installed and configured everything like said on the github page.
When running the following suggested curl command
curl -X POST -H "Content-Type: application/json" http://127.0.0.1:8000/app_dev.php/api/login_check -d "{\"username\":\"johndoe\",\"password\":\"test\"}"
I allways get the following 401 response.
The response is the same for a non existing user or wrong password as well as for an existing valid user with correct password.
{"code":401,"message":"Bad credentials"}
My setup is the following:
config.yml:
(if I need to add more details let me know)
lexik_jwt_authentication:
secret_key: "%kernel.root_dir%/config/jwt/private.pem" # required for token creation
public_key: "%kernel.root_dir%/config/jwt/public.pem" # required for token verification
pass_phrase: "%jwt_key_pass_phrase%" # required for token creation, usage of an environment variable is recommended
token_ttl: "%jwt_token_tll%"
security.yml:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
...
providers:
in_memory:
memory: ~
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 for Lexik Json Web Token Authentication
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
require_previous_session: false
# API for Lexik Json Web Token Authentication
api:
pattern: ^/api
stateless: true
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
main:
pattern: ^/
form_login:
provider: fos_userbundle
check_path: fos_user_security_check
login_path: fos_user_security_login
csrf_token_generator: security.csrf.token_manager
default_target_path: fos_user_profile_show
always_use_default_target_path: true
logout:
path: fos_user_security_logout
target: default_loged_out_target
logout_on_user_change: true
anonymous: true
switch_user:
role: ROLE_ADMIN
provider: fos_userbundle
remember_me:
secret: '%secret%'
lifetime: 15552000
path: /
access_control:
...
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
routing.yml:
...
api_login_check:
path: /api/login_check
So - like said I allways get this response:
{"code":401,"message":"Bad credentials"}
Can anyone point into the right direction on how to fix this?
Everything seems to be OK but I suspect that since you have two providers (in_memory and fos_userbundle) from which of them does Lexik JWT looks for the credentials ? If you don't use the in_memory provider, you should try to remove it.
Related
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 _)
I'm using Symfony 4.1.7 in my security.yaml have this access control:
access_control:
# master:
- { path: ^/master, roles: ROLE_MASTER }
# manager:
- { path: ^/.*/manager, roles: ROLE_MANAGER }
# main:
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
when i open the second one url (/foo/manager) and not authorized i will redirected to login path i need to return access denaid not redirect to login.
my last goal is call event listener for append role to authorize user from event listener.
Update:
Here is my security firewall section:
main:
pattern: ^/
user_checker: App\Security\Checker\UserChecker
anonymous: ~
provider: default
context: primary
simple_form:
authenticator: App\Security\Authenticator\UserAuthenticator
check_path: login
login_path: login
username_parameter: phone
password_parameter: password
use_referer: true
logout:
path: logout
remember_me:
secret: '%kernel.secret%'
lifetime: 604800
path: /
remember_me_parameter: remember_me
Yo need to configure the login_path en the security.yml
Example:
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
in_memory: { memory: ~ }
encoders:
FOS\UserBundle\Model\UserInterface: sha512
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: .*
context: user
form_login:
provider: fos_userbundle
login_path: /login
use_forward: false
check_path: /login_check
failure_path: null
Symfony Doc.
You have to allow users to access this path and instead use your controller to check the user role.
$this->denyAccessUnlessGranted('ROLE_MANAGER ', null, 'Unable to access this page!');
or
$this->isGranted('ROLE_MANAGER');
Depending on what you want to do.
I'm working with ldaptools-bundle, fosuserbundle in an api endpoint.
My security.yaml looks like this
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
LdapTools\Bundle\LdapToolsBundle\Security\User\LdapUser: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
chain_provider:
chain:
providers: [ldap, fos_userbundle]
fos_userbundle:
id: fos_user.user_provider.username_email
ldap:
id: ldap_tools.security.user.ldap_user_provider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/login
stateless: true
anonymous: true
provider: ldap
json_login:
check_path: /login
username_path: username
password_path: password
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
guard:
authenticators:
- ldap_tools.security.ldap_guard_authenticator
main:
pattern: ^/
provider: fos_userbundle
stateless: true
anonymous: true
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
the problem is thath the ldap guard authenticator is not checking the credentials.
When I change the provider to ldap instead fosuser I got a 500 error code in BasePasswordEncoder class, it happens also if I use the chain_provider
Warning: hash_equals(): Expected known_string to be a string, null
given
Is there a miss config or something?
The workflow should be as follow:
The user is authenticated against ldap server
The user is loaded correctly and then lexik takes care of the token generation
Note: The workflow works without ldap and the token is generated.
Thanks in advance!
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 }
I am using LexikJWTBundle for a RESTful API.
Login works just fine and I get my token. But when I make a GET request I get a 401 with no content.
The Authorization header seems ok since I get this in the profiler:
Request Headers: authorization: Bearer {token}
Request Server Parameters: HTTP_AUTHORIZATION: Bearer {token}
The 401 I get is from: https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Security/Firewall/JWTListener.php#L80
I've tried different solutions but still it's not working.
Would you have any idea on how to resolve/debug this?
My config:
# config.yml
...
lexik_jwt_authentication:
private_key_path: %kernel.root_dir%/var/jwt/private.pem # ssh private key path
public_key_path: %kernel.root_dir%/var/jwt/public.pem # ssh public key path
pass_phrase: 'TEST' # ssh key pass phrase
token_ttl: 86400 # token ttl - defaults to 86400
And
# security.yml
security:
role_hierarchy:
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_SONATA_ADMIN, ROLE_ALLOWED_TO_SWITCH]
# http://sonata-project.org/bundles/admin/2-3/doc/reference/security.html
# set access_strategy to unanimous, else you may have unexpected behaviors
access_decision_manager:
strategy: unanimous
encoders:
FOS\UserBundle\Model\UserInterface: sha512
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api_login:
pattern: ^/api/login # Default: .*
provider: fos_userbundle
# form login
form_login:
login_path: fos_user_security_login
# csrf_provider: form.csrf_provider # Default: my.csrf_provider.id
# LexikJWT # 09/01/15 - Note: provient de la configuration officielle.
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
anonymous: true # Default: ~
api:
pattern: ^/api
stateless: true
lexik_jwt:
authorization_header: # check token in Authorization Header
enabled: true
prefix: Bearer
anonymous: true
access_control:
# 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: "^/api/contacts$", roles: IS_AUTHENTICATED_ANONYMOUSLY, methods: [POST] }
- { path: "^/api/users/dt$", roles: IS_AUTHENTICATED_ANONYMOUSLY, methods: [GET] }
- { path: "^/api/users$", roles: IS_AUTHENTICATED_ANONYMOUSLY, methods: [POST] }
- { path: "^/api", roles: [IS_AUTHENTICATED_FULLY, ROLE_API] }
I just found a solution on the same problem
Here my security.yml
firewalls:
dev:
pattern: ^/(_(profiler|wdt|error)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
anonymous: true
provider: user_db
form_login:
check_path: /api/login_check
username_parameter: _username
password_parameter: _password
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
lexik_jwt:
authorization_header: # check token in Authorization Header
enabled: true
prefix: Bearer
throw_exceptions: false # When an authentication failure occurs, return a 401 response immediately
create_entry_point: true # When no authentication details are provided, create a default entry point that returns a 401 response
authentication_provider: lexik_jwt_authentication.security.authentication.provider
My problem was the username and the password parameters. I change "username" by "_username" and "password" by "_password"
You should add the ROLE_API in the role_hierarchy of your security.yml :
role_hierarchy:
# ...
ROLE_API: [ROLE_USER]
Then, users ranked with ROLE_API can access routes restricted to IS_AUTHENTICATED_FULLY.
Also, if you are using a web server, try to use your application using the built-in server (i.e. app/console server:run).
Apache seems to modify the token in headers.
LexikJWTBundle generates token so user's credentials are valid.
Problem occurs when you try to access secured routes (behind "^/api" path).
You should definitely check roles assigned to user. Maybe ROLE_API is missing and user is not fully authenticated.