Main menu

Pages

Symfony 6 JWT authentication in 5 minutesToday we are going to see how to secure a Symfony 6 API with JSON Web Tokens (JWT).In this tutorial, we will review together the basics of a REST API and then focus on JWT tokens.


API

API (Application Programming Interface). An interface is a means of communicating between 2 entities according to standards. This can be, for example, a restaurant menu that allows you to communicate between you and the restaurant kitchen. The standards here are the menu list: you can only ask for the dishes available on the menu.


The REST form


The structure of URLs


URL addresses are made up of an entry point followed by the name of the resources that you want to obtain or modify. 


Example


If I want to retrieve users, Localhost/API/users.

If they are articles, we will target Localhost/API/articles.

To modify a resource, you specify its ID in the route,


Example


If I want to retrieve user byId

Localhost/API/users/id 

If I want to retrieve article byId

Localhost/API/articles/id.


HTTP Verbs


Each request made must correctly describe the action it wishes to perform with the server. If it is not correct, the server will return an error. There are 4 main possible actions:


  • GET for data recovery
  • POST for creating data
  • PUT for data modification
  • DELETE for deleting data


Response codes


For each request made, the server will send you a specific HTTP code. Without going into detail, we can cite the codes 200 when everything is going well, 400 when there has been an error in the data sent by the client, and also 500 when there has been an error on the server side.


Stateless


The Rest API must be “stateless” or “stateless” in French. By this, we mean having no session information. The server must have, for a request, all the data necessary to process the request. He should neither worry about your past requests nor your future ones.


Versioning


The sites evolve, and you can imagine the APIs too. APIs must also be versioned. Ideally, we suffix the API entry point with a version number. Example: localhost/API/v1/users then, localhost/API/v2/users


The documentation


If you open your data via an API to the public or to certain collaborators, they must understand how to interact with your API. Document! It is necessary that for each available route, we can understand its operation and the expected parameters possibly. We also need to understand what the server sends back to us and in what form!


JWT(JSON web token)


A JWT token is a string of characters that we will send to each request that we want to make to an API in order to authenticate. It contains all the information necessary for our identification (remember that we are in a Stateless system and that the server does not store our identification information in the session, for example!).


This token is made up of three parts:


  • The header, which contains the algorithm used for signing the token,
  • The payload of the token, which contains our user data, for example, our user name, as well as other useful information such as the expiry date of the token, its creation date, etc.,
  • And finally, the signature of the token.

The first two parts are base64 encoded JSON objects and the last part is the result of encoding the first two parts with the algorithm defined in the header.


In addition to this useful information, there are some reserved properties/keywords. Here is a non-exhaustive list :


  • Iss: lets you know who issued the token,
  • Sub: the unique identifier of the token user. Often the user ID or his username/email,
  • Exp: the timestamp from which the token will no longer be valid,
  • Iat: the time the token was issued.


Symfony 6 jwt authentication in 5 minutes


Setting up jwt authentication in symfony 6


Setting up the database,entity user


1) first of all, we gonna create a new Symfony project and prepare the database


composer create-project symfony/website-skeleton projectname


2) Setting up the database URL


DATABASE_URL="mysql://root:@127.0.0.1:3306/jwtauth?serverVersion=mariadb-10.4.21"


php bin/console doctrine:database:create


3) now we gonna create a new User 


php bin/console make:user


4) Making migration


php bin/console make:migration


5) Execute migration


php bin/console doctrine:migrations:migrate


In the next step we gonna add a new user in the database manually in PHPMyAdmin, we need to enter a hashed password also manually so we need to execute this command in the terminal.

php bin/console security:hash-password


lexik jwt authentication


1) First, we will install the lexik jwt authentication bundle using this composer command:


Composer require lexik/jwt-authentication-bundle


2) And now the secret magic command to generate automatically JWT_SECRET_KEY and JWT_PUBLIC_KEY.


php bin/console lexik:jwt:generate-keypair

this command will create jwt folder in the config directory and will generate a secret key and a public key.


3) Now we need to configure security.yaml like this


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'
    # 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
            provider: app_user_provider
            json_login:
                username_path: email
                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
            jwt: ~


4) Make sure to remove


main:
            lazy: true
            provider: app_user_provider

5) now we need to configure our route in routes.yaml


api_login_check:
    path: /api/login_check

6) Add user identity email in config/packages/lexik_jwt_authentication.yaml


    user_identity_field : email

That's all now our jwt token is ready to use, thank you and if u have any questions make sure to post ur questions on full tutorial in my youtube channel.