Émettre un JSON Web Token
Qu’est-ce qu’un JSON Web Token ?
Un JSON Web Token, ou JWT est une chaîne de caractères encodée en base64 qui contient des informations concernant le porteur (Bearer). Les JWT sont définis depuis 205 par la RFC 7519 : https://datatracker.ietf.org/doc/html/rfc7519
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwi
bmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2Q T
4fwpMeJf36POk6yJV_adQssw5c
Un JWT est en trois parties distinctes séparées par un point. L’en-tête qui contient des informations techniques :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
{
"alg": "HS256",
"typ": "JWT"
}
Le corps, qui contient les informations du porteur :
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
Et la signature :
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
La signature permet de vérifier que les données du token n’ont pas été modifiées.
Les données du token n’étant pas cryptées, mais juste encodées en base64 pour en faciliter le transport dans les en-têtes...
Créer un JWT
Le JWT que nous allons émettre devant être signé, nous utiliserons pour cela une clé asymétrique tout au long de ce chapitre. C’est la méthode la plus facile à mettre en œuvre, car elle ne suppose pas de partager une clé entre le SSO et les applications qui devront valider le token. Dans le cas d’une clé asymétrique, le SSO met à disposition de tous la clé publique, ce qui permettra à toute application devant valider un token de venir se servir. Ceci est beaucoup plus flexible pour ses propres applications bien sûr, mais d’autant plus si on souhaite ouvrir notre SSO à des tiers. Pour diffuser la clé publique, nous avons besoin d’une méthode qui permet d’exposer celle-ci.
Commençons par créer le service qui va gérer les clés de cryptage :
public interface ISigningCredentialsService
{
void AddSignInCredentials(SigningCredentials credentials);
SigningCredentials GetSignInCredentials();
IEnumerable<object> GetKeys();
}
L’interface ISigningCredentialsService expose trois méthodes :
-
AddSignInCredentials() permettra d’ajouter les clés dans un conteneur.
-
GetSignInCredentials() permettra de récupérer une clé dans le conteneur pour crypter notre token.
-
GetKeys() permettra de récupérer l’ensemble des clés pour exposer leur partie publique.
L’implémentation de l’interface :
public class SigningCredentialsService : ISigningCredentialsService
{
private List<SigningCredentials> _signInCredentials;
public SigningCredentialsService()
{
_signInCredentials = new();
}
public void AddSignInCredentials(SigningCredentials credentials)
=> _signInCredentials.Add(credentials);
public IEnumerable<object> GetKeys()
=> _signInCredentials.Select(s => (JsonWebKey)s.Key).Select(s => ...
Valider un JWT
Vous pouvez tester votre token sur JWT.io :
En copiant votre token dans la fenêtre de saisie de gauche et le JSON de la clé dans la partie clé publique, JWT.io vous indiquera que votre signature a été vérifiée et donc votre token est valide. Une application qui consommerait votre JWT ferait exactement la même chose en allant chercher les informations de la clé publique sur un endpoint dédié. Une fois la clé publique en sa possession, elle a la possibilité de valider l’authenticité et l’intégrité des tokens cryptés avec la clé privée correspondante.
Félicitations ! Vous venez d’implémenter manuellement un système d’authentification par token JWT qui est utilisé par la majeure partie des applications web modernes.
Toutefois, cet exemple très simple n’a pour vocation que de vous montrer le sous-jacent de cette technologie afin que vous en compreniez les subtilités. En aucun cas, ne déployez ce genre de chose en production tant ce système est basique et présente des manques.
Nous allons maintenant nous pencher sur le protocole OAuth2 et sa surcouche OpenID Connect qui sont des protocoles de sécurité basés sur l’utilisation des JWT. C’est donc ce que l’on vient de faire, en (beaucoup) plus abouti....