'Lexik JWT authentication problem "Invalid credentials"
I am new to symfony and I am using LexikJWTAuthenticationBundle for authorization. I am using symfony 6.0.2 and 2.14 lexic version. I am using Postgresql 12.9. My security.yaml:
security:
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
App\Entity\User:
algorithm: auto
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
login:
pattern: ^/api/login
stateless: true
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
jwt: ~
main:
lazy: true
provider: app_user_provider
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall
# 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: ^/api/login, roles: PUBLIC_ACCESS }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
when@test:
security:
password_hashers:
# By default, password hashers are resource intensive and take time. This is
# important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon
My fos_rest.yaml:
# Read the documentation: https://symfony.com/doc/master/bundles/FOSRestBundle/index.html
fos_rest:
body_listener:
enabled: true
# param_fetcher_listener: true
# allowed_methods_listener: true
# routing_loader: true
# view:
# view_response_listener: true
# exception:
# codes:
# App\Exception\MyException: 403
# messages:
# App\Exception\MyException: Forbidden area.
format_listener:
rules:
- { path: ^/api, prefer_extension: true, fallback_format: json, priorities: [ json ] }
My 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: 3600
My database was configured correctly and it is working and my passphrase is also correct My user entity is this:
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* @ORM\Entity(repositoryClass="App\Repository\UserRepository")
* @ORM\Table(name="`user`")
*/
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
/**
* @ORM\Id()
* @ORM\GeneratedValue(strategy="IDENTITY")
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=180, unique=true)
*/
private $email;
/**
* @ORM\Column(type="json")
*/
private $roles = [];
/**
* @var string The hashed password
* @ORM\Column(type="string")
*/
private $password;
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUserIdentifier(): string
{
return (string) $this->email;
}
/**
* @see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* @see PasswordAuthenticatedUserInterface
*/
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* @see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
}
I am sending this request:
{
"username": "azamjon",
"password":"1234"
}
Database have these informations What I am making wrong? The response is :
{
"code": 401,
"message": "Invalid credentials."
}
routes.yaml:
# controllers:
# resource: ../src/Controller/
# type: annotation
# kernel:
# resource: ../src/Kernel.php
# type: annotation
products:
path: /api/product
controller: App\Controller\ProductController::indexAction
methods : [GET]
products_store:
path: /api/product_store
controller: App\Controller\ProductController::createAction
methods : [POST]
products_show:
path: /api/product_show/{id}
controller: App\Controller\ProductController::showAction
methods : [GET]
products_delete:
path: /api/product_delete/{id}
controller: App\Controller\ProductController::deleteAction
methods : [DELETE]
products_update:
path: /api/product_update/{id}
controller: App\Controller\ProductController::products_update
methods : [PATCH]
# register:
# path: /api/register
# controller: App\Controller\AuthController::register
# methods: POST
api_login_check:
path: /api/login_check
Solution 1:[1]
I had the same issue, it was because the password was not hashed in my database... care about this and config :
# security.yaml
login:
pattern: ^/api/login
stateless: true
json_login:
check_path: /api/login_check
username_path: email
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
# 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: 3600
user_identity_field: email
Solution 2:[2]
You can use the option user_identity_field: email
since default is set to username
in lexik_jwt_authentication.yaml
#config/packages/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: 3600
user_identity_field: email
Also you can add username_path
to your security.yaml
for less confusion:
#config/packages/security.yaml
json_login:
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
username_path: email
password_path: password
Solution 3:[3]
You must check if the password hashing done while registering the user is done using the password-hasher bundle
composer require symfony/password-hasher
therefore, make sure to follow the documentation : Password-hasher in symfony
and, implement the password hasher to register the user.
Solution 4:[4]
You try to login with username but, symfony wait e-mail
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: email
Try to replace property: email
to property: username
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | S.Luja |
Solution 4 | Kallard |