Création d'un jeton d'authentification

Contexte

Vous allez tout d'abord utiliser et configurer le bundle Lexic Authentication JWT dans une application Symfony sans API Platform.

Mais avant d'installer ce bundle, comprenez comment les JWT fonctionnent.

Un JWT est une chaine de caractères encodée qui doit être envoyée par le client à chaque requête. Cette chaîne de caractères permet à l'API d'authentifier l'utilisateur afin de lui permettre d'accéder à ses diverses fonctionnalités.

Afin que le serveur puisse identifier le client, le token doit se structurer en trois parties :

  • Un header en JSON, contenant notamment l'algorithme utilisé pour générer la signature. Il décrit aussi le token.

  • Un payload en JSON, contenant les informations que l'on souhaite transmettre, par exemple l'identifiant de l'utilisateur.

  • Une signature, très importante, créée à partir du header, du payload et d'une clé secrète.

Ces trois parties sont assemblées pour former le token.

Quand le client s'authentifie correctement, ce token, généré par le serveur, est envoyé au client. À chaque requête, le token est renvoyé par le client au serveur et il suffit au serveur de vérifier la signature afin de savoir si le token est valide. S'il est valide, alors les informations dans le payload peuvent être utilisées pour, par exemple, identifier l'utilisateur.

Ce processus est critique à la sécurité de l'application. C'est pour cela que l'on utilise des librairies éprouvées comme Lexic Authentication JWT afin de créer et manipuler les JWT.

Grâce à ce bundle, vous allez sécuriser votre API Symfony afin que seuls les utilisateurs authentifiés puissent accéder aux divers points d'API de vos articles.

Remarque

Afin de bénéficier de points d'API déjà fonctionnels, une API déjà créée sera utilisée ici.

Avant de pouvoir utiliser le bundle, toutes les URLs doivent cependant être préfixées par « /api ». Il faut également qu'une entité User soit créée avec la commande make:auth (rappel ici : Symfony Docs ) et qu'un utilisateur soit bien sûr enregistré en base de données.

Méthode

Afin d'installer le bundle, il faut utiliser composer :

ExempleCode

1
composer require lexik/jwt-authentication-bundle

Méthode

La première étape est de générer des clés publiques et privées à l'aide, par exemple, de l'utilitaire OpenSSL que vous pouvez installer sous Windows, Mac ou Linux. Ces clés seront utilisées par le bundle afin de signer et valider les tokens.

Dans le dossier « config » de l'application Symfony, créez un nouveau dossier « jwt ». Vous allez y stocker les clés. Placez vous dans ce dossier, cliquez droit « ouvrir dans un terminal » puis exécuter la ligne de commande suivante afin de générer la clé privée :

ExempleCode

1
openssl genrsa -out private.pem -aes256 4096

Méthode

Lors de la génération, un mot de passe devra être créé. Veuillez le conserver car il vous sera redemandé.

Vous allez créer la clé publique avec cette commande :

ExempleCode

1
openssl rsa -pubout -in private.pem -out public.pem

Complément

Voici une guidance sur la génération de clés sur OpenSSL.

Méthode

Une fois ces clés générées, vous allez devoir renseigner leur chemin, ainsi que le mot de passe utilisé, dans des variables d'environnement spécifiques (à l'intérieur du fichier « .env.local »). Ces variables d'environnements sont utilisées par défaut par le fichier « config/package/lexik_jwt_authentication.yaml » afin de générer les tokens.

ExempleCode

1
###> lexik/jwt-authentication-bundle ###
2
3
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
4
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
5
JWT_PASSPHRASE=MotDePasseUtiliséPourGénérerLesClefs
6
7
###< lexik/jwt-authentication-bundle ###

Méthode

Maintenant que les clés sont générées et utilisables par le bundle pour authentifier les utilisateurs, il faut configurer les règles de sécurité de Symfony afin qu'il protège toutes les URLs d'API en utilisant le mécanisme de JWT géré par le bundle. Ces informations sont à ajouter dans le fichier « config/packages/security.yaml » :

ExempleCode

1
security:
2
    encoders:
3
        App\Entity\User:
4
            algorithm: auto
5
6
    providers:
7
        # used to reload user from session & other features (e.g. switch_user)
8
        app_user_provider:
9
            entity:
10
                class: App\Entity\User
11
                property: username
12
13
    firewalls:
14
        dev:
15
            pattern: ^/(_(profiler|wdt)|css|images|js)/
16
            security: false
17
        login:
18
            pattern:  ^/api/login
19
            stateless: true
20
            anonymous: true
21
            json_login:
22
                check_path:               /api/login_check
23
                success_handler:          lexik_jwt_authentication.handler.authentication_success
24
                failure_handler:          lexik_jwt_authentication.handler.authentication_failure
25
        api:
26
            pattern:   ^/api
27
            stateless: true
28
            guard:
29
                authenticators:
30
                    - lexik_jwt_authentication.jwt_token_authenticator
31
32
    access_control:
33
        - { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
34
        - { path: ^/api,       roles: IS_AUTHENTICATED_FULLY }

Dernière étape, il faut créer la route « /api/login » (celle renseignée dans le fichier de configuration de la sécurité) afin que le client puisse envoyer son nom et son mot de passe en POST, à la suite de quoi le serveur lui renverra le token.

Dans le fichier routes.yaml, il faut ajouter les lignes suivantes :

ExempleCode

1
authentication_token:
2
  path: /api/login
3
  methods: ['POST']

Et le tour est joué !

Désormais, toutes les URLs commençant par « /api » nécessitent une authentification et ne sont pas accessibles tant que l'utilisateur n'envoie pas dans sa requête un token valide.

Pour récupérer ce token, le client doit faire une requête POST sur l'URL : « /api/login ». Cette requête doit contenir dans le body le nom de l'utilisateur ainsi que son mot de passe. Si ces identifiants sont valides, alors votre API, à l'aide du bundle, retourne un token au client.

Ensuite, pour accéder aux ressources de votre API, le client doit renseigner pour chaque requête ce token dans un header « authorisation » de type « Bearer Token ». Si le token est validé, alors votre serveur donne au client le droit d'accéder aux URLs demandées.

Votre API est maintenant sécurisée !

Fondamental

  • Dans une API, les utilisateurs sont généralement authentifiés en utilisant le mécanisme de JWT, alias JSON Web Token.

  • Quand un client s'authentifie auprès de l'API, l'API lui renvoie un token. Ce token sera utilisé par le client à chaque nouvelle requête afin de vérifier son identité.

  • La génération et la gestion de ces tokens sont un processus complexe et critique pour la sécurité de l'application et il est conseillé d'utiliser des librairies connues pour mettre en place ces fonctionnalités.

  • Dans une application Symfony, le bundle Lexic Authentication JWT peut être utilisé.