Modern Enterprise Software Applications are implemented with a backend following the Http Rest Api pattern. Each request must include an "Authorization" header with a Bearer Token as value. JWT tokens are becoming the more secure way to authenticate requests. The most common way to get a JWT from the Backend Application is implementing an "authenticate" endpoint that receives the User's username and password. You can use the endpoint provided by the lexik/jwt-authentication-bundle or you can implement your own. Follow these steps to do this:
Prerequisites: How to generate a JWT json web token in symfony framework.
Step 1. Install the necessary packages:
composer require lexik/jwt-authentication-bundle
composer require symfony/security-bundle
Step 2. Configure your security.yaml file by adding the following lines:
security:
encoders:
App\Entity\User:
### lib-sodium available in your machine
### If not use bcrypt
algorithm: sodium
providers:
app_user_provider:
entity:
class: App\Entity\User
###This is the username
property: email
firewalls:
login:
pattern: ^/api/login
stateless: true
anonymous: true
json_login:
check_path: /api/login
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
access_control:
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
Step 3. Create a route for handling the login request in your routes.yaml file or you may better use the new recommended way with Symfony Annotations as shown in Step 4.:
login:
path: /api/login
controller: App\Controller\AuthController::login
Step 4. Create an AuthController class and implement the login method:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\User\UserInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
class AuthController extends AbstractController
{
/**
* @Route("/api/login", methods={"POST"}, defaults={"_format": "json"})
* @param Request $request
* @param JWTTokenManagerInterface $jwtManager
* @param UserPasswordEncoderInterface $passwordEncoder
* @param EntityManagerInterface $em
* @return JsonResponse
*/
public function login(Request $request, JWTTokenManagerInterface $jwtManager, UserPasswordEncoderInterface $passwordEncoder, EntityManagerInterface $em)
{
$user = $em->getRepository(User::class)->findOneBy(['email' => $request->request->get('username')]);
if (!$user) {
throw new BadCredentialsException();
}
$isValid = $passwordEncoder->isPasswordValid($user, $request->request->get('password'));
if (!$isValid) {
throw new BadCredentialsException();
}
$token = $jwtManager->create($user);
return new JsonResponse(['token' => $token]);
}
}
Step 5. Test your endpoint by sending a POST request to /api/login with a JSON payload containing the username and password fields:
{
"username": "This email address is being protected from spambots. You need JavaScript enabled to view it.",
"password": "password123"
}
Important!: As best practice and to prevent security breaches, send hashed passwords with an algorithm that can be implemented in the frontend application that can be de-hashed by the backend.