here is my set up :
Back : Symfony 6.1
Front : React
To get logged in, I use the JWT token of lexik bundle, which works grea. When logging in, I get my token and set it in a cookie, I get my current user in front.
But ine the back part, when I try to get the current user, it always returns null. Trying to do a Patch method returns an internal server error, saying basically that the current user is not found, which is strange as I am logged in on my post endpoint.
Here is my PATCH method, that is supposed to modify user’s informations :
#[Route('/api/users', name: 'api_modify', methods: "PATCH")]
public function updateUser(User $user = null, Request $request): Response
{
$data = $request->getContent();
$user = $this->getUser();
try {
$updatedUser = $this->serializer->deserialize($data, User::class, "json");
} catch (NotNormalizableValueException $e) {
return new JsonResponse("Erreur de type pour le champ '". $e->getPath() . "': " . $e->getCurrentType() . " au lieu de : " . implode('|', $e->getExpectedTypes()), Response::HTTP_UNPROCESSABLE_ENTITY);
}
$user
->setPassword($this->hasher->hashPassword($updatedUser, $updatedUser->getPassword()))
->setFirstname($updatedUser->getFirstName())
->setLastname($updatedUser->getLastName())
->setEmail($updatedUser->getEmail())
;
$errors = $this->validator->validate($user);
if (count($errors) > 0) {
$myJsonError = new JsonError(Response::HTTP_UNPROCESSABLE_ENTITY, "Des erreurs de validation ont été trouvées");
$myJsonError->setValidationErrors($errors);
return $this->json($myJsonError, $myJsonError->getError());
}
$this->manager->flush();
return $this->json(
$user, Response::HTTP_OK,
[],
['groups' => ['show_user']]
);
}
And here is my front api call, made in my component :
export const Changeinfo = () => {
const { register, handleSubmit, setValue, formState: { errors } } = useForm();
const dispatch = useDispatch();
const navigate = useNavigate();
const changeinfoOnSubmit = async (data) => {
try {
let token = localStorage.getItem('token');
const response = await axiosInstance.patch("https://stackoverflow.com/users", data, {
headers: {
'Authorization': `Bearer ${token}`
}
});
dispatch(changeinfo(response.data));
} catch (error) {
console.error('Erreur lors du login', error);
}
};
function getUser() {
return JSON.parse(localStorage.getItem('user'));
}
const user = getUser();
useEffect(() => {
if (user && user.email) {
setValue('email', user.email);
}
if (user && user.lastname) {
setValue('lastname', user.lastname);
}
if (user && user.firstname) {
setValue('firstname', user.firstname);
}
}, [user, setValue]);
return (
<div className={styles.Changeinfo}>
<Navigation />
<div className={styles.Changeinfo__cabinet}>
<img src={image} alt="" />
<h1>Mon espace membre</h1>
</div>
<form onSubmit={handleSubmit(changeinfoOnSubmit)}>
<div>
<input
type="text"
name="email"
placeholder="Email"
{...register('email', { required: true })}
/>
{errors.username && <p>Le nom d'utilisateur est requis</p>}
</div>
<div>
<input
type="password"
name="password"
placeholder="Mot de passe"
{...register('password', { required: true })}
/>
{errors.password && <p>Le mot de passe est requis.</p>}
</div>
<div>
<input
type="text"
name="lastname"
placeholder="Nom de famile"
{...register('lastname', { required: true })}
/>
{errors.lastname && <p>Le nom de famille est requis</p>}
</div>
<div>
<input
type="text"
name="firstname"
placeholder="Prénom"
{...register('firstname', { required: true })}
/>
{errors.firstname && <p>Le prénom est requis</p>}
</div>
<button>Enter</button>
</form>
</div>
)
}
I send back the token with the right informations,but here is the message I get :
PATCH http://localhost:8739/api/users 500 (Internal Server Error)
Changeinfo.jsx:30 Erreur lors du login AxiosError {message: ‘Request failed with status code 500’, name: ‘AxiosError’, code: ‘ERR_BAD_RESPONSE’, config: {…}, request: XMLHttpRequest, …}
When trying from Postman, the error points that $this->getUser() is the source of the problem.
How is it possible that I can logging easily, but the user back side remains null ?
My security.yml :
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: ~
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
custom_authenticator: App\Security\LoginFormAuthenticator
logout:
path: app_logout
# where to redirect after logout
# target: app_any_route
# 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: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/api/login, roles: PUBLIC_ACCESS }
- { path: ^/api/signup, roles: PUBLIC_ACCESS }
#- { path: ^/api/users, roles: IS_AUTHENTICATED_FULLY }
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 # in seconds, default is 3600
Well, in my security.yaml I have some access control configured, and firewall but that’s all. I am using LexikJWTAuthenticationBundle, version 2.19.1.
I put it in answer, was too long to post here
Can you uncomment your access control line concerning api/users
- { path: ^/api/users, roles: IS_AUTHENTICATED_FULLY }
and try again ?I get a 401 because according to symfony, i’m not fully authenticated. In my controller, $this->getUser() returns null. That is the real problem I guess { “code”: 401, “message”: “JWT Token not found” }
Did you get a JWT Token not found error ? have you checked if your request contains your token ?
Show 1 more comment