Comment gérer les jetons invalides dans les applications web et mobiles ?

JWT

Alors que les applications web et mobiles dépendent de plus en plus d’API tierces, il est critique de gérer efficacement les jetons (tokens) émis par les flux OpenID Connect. Les jetons sont utilisés pour authentifier et autoriser les utilisateurs. Lorsqu’ils deviennent invalides, ils peuvent causer divers problèmes, notamment des requêtes échouées, des vulnérabilités de sécurité et une mauvaise expérience utilisateur.

OpenID Connect est un protocole d’authentification construit au-dessus d’OAuth2 qui permet aux clients de vérifier l’identité des utilisateurs finaux sur la base de l’authentification effectuée par un serveur d’autorisation. Lorsqu’un utilisateur se connecte à une application utilisant OpenID Connect, le serveur d’autorisation émet un jeton d’accès que l’application utilise pour accéder aux ressources de l’utilisateur sur l’API.

Lorsque le jeton d’accès devient invalide, il est essentiel de détecter et de gérer ce problème de manière efficace afin de ne pas nuire à l’expérience de l’utilisateur. Dans les sections suivantes, nous aborderons différentes approches pour détecter et gérer les jetons invalides dans les applications web et mobiles.

Détection des jetons invalides

La détection des jetons invalides est la première étape pour les gérer efficacement. Un jeton invalide est un jeton expiré, révoqué ou jugé non valide selon les règles du serveur d’authentification. La technique la plus courante pour détecter un jeton invalide consiste à envoyer une requête au serveur d’authentification et à vérifier la réponse.

Il existe deux types de jetons invalides qui peuvent être détectés :

  • Codes de réponse HTTP : Une autre façon de détecter un jeton invalide consiste à examiner les codes de réponse HTTP du serveur de ressources. Si le serveur de ressources renvoie un code de réponse 401 Unauthorized, cela indique que le jeton est invalide ou a expiré. Dans ce cas, le client doit demander un nouveau jeton d’accès en utilisant l’une des stratégies présentées dans la section suivante.
  • Jetons expirés : Les jetons d’accès ont une durée de vie limitée, généralement mesurée en minutes ou en heures. Une fois le jeton expiré, il ne peut plus être utilisé pour accéder aux ressources de l’utilisateur. Pour détecter les jetons expirés, le client peut comparer l’heure d’expiration du jeton avec l’heure actuelle sur l’appareil ou le serveur. Si le jeton a expiré, le client doit demander un nouveau jeton d’accès en utilisant l’une des stratégies présentées dans la section suivante.
  • Jetons révoqués ou invalides : Parfois, les jetons d’accès deviennent invalides avant leur heure d’expiration. Cela peut se produire si l’utilisateur révoque son consentement d’accès pour l’application, ou si le serveur d’authentification détecte une activité suspecte liée au jeton. Pour détecter les jetons révoqués ou invalides, le client doit envoyer une requête au point de terminaison d’introspection de jeton (token introspection endpoint) fourni par le serveur d’authentification. Ce point de terminaison renvoie un objet JSON contenant des informations sur le jeton, notamment s’il est toujours valide.

Exemple avec Axios

En ajoutant un intercepteur à la chaîne de réponse de l’instance Axios, nous pouvons intercepter les erreurs 401 et les traiter en conséquence. Dans ce cas, nous journalisons un message indiquant que le jeton est invalide et doit être rafraîchi, puis nous pouvons procéder à la demande d’un nouveau jeton d’accès et rejouer la requête d’origine.

Intercepter les requêtes de cette manière est très utile pour gérer l’expiration ou la révocation des jetons, ainsi que d’autres types d’erreurs pouvant survenir lors des appels API. Cela vous permet de centraliser votre logique de gestion des erreurs et d’éviter de répéter du code dans toute votre application.

Voici un exemple d’interception de chaque requête effectuée avec une instance Axios et de gestion des erreurs 401 Unauthorized :

import axios from 'axios'
const API_URL = 'https://example.com/api'
const ACCESS_TOKEN = 'abc123' // à remplacer par votre véritable jeton d'accès
const axiosInstance = axios.create({
baseURL: API_URL,
headers: {
Authorization: `Bearer ${ACCESS_TOKEN}`,
},
})
axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
if (error.response.status === 401) {
// gestion du jeton invalide
console.log("Jeton invalide - demande de nouveau jeton d'accès")
// demander un nouveau jeton d'accès et réessayer la requête
// note : vous pouvez accéder à la configuration de la requête d'origine avec error.config
}
return Promise.reject(error)
},
)
// exemple de requête
axiosInstance
.get('/resource')
.then((response) => {
// gérer la réponse réussie
})
.catch((error) => {
// gérer les autres erreurs
console.log('Erreur :', error.message)
})

Note que cette approche suppose que le serveur d’API renvoie un code d’erreur 401 lorsque le jeton d’accès est invalide. Si votre serveur d’API utilise un code d’erreur différent pour indiquer un jeton invalide, vous devrez adapter le code en conséquence.

Il est important de noter que différents serveurs d’authentification peuvent avoir des règles et des mécanismes différents pour détecter les jetons invalides. Les développeurs doivent consulter la documentation du serveur d’authentification pour déterminer la meilleure approche dans leur cas d’utilisation particulier.

Dans la section suivante, nous aborderons les différentes stratégies que les développeurs peuvent utiliser pour gérer les jetons invalides une fois qu’ils ont été détectés.

Le rafraîchissement des jetons comme solution

Le rafraîchissement des jetons est une solution courante pour gérer les jetons invalides dans les applications web et mobiles s’appuyant sur OpenID Connect ou OAuth. Avec cette méthode, lorsque le jeton d’accès d’un utilisateur expire ou devient invalide, un nouveau jeton d’accès est demandé sans exiger que l’utilisateur se reconnecte. Cela permet à l’utilisateur de conserver sa session active et de continuer à utiliser l’application sans interruption.

Comment fonctionnent les jetons de rafraîchissement (Refresh Tokens) dans OpenID Connect et OAuth

Dans OpenID Connect et OAuth, un jeton de rafraîchissement (refresh token) est émis en même temps qu’un jeton d’accès lorsqu’un utilisateur se connecte ou accorde l’accès à une application. Le jeton de rafraîchissement est le plus souvent un jeton à longue durée de vie qui peut être utilisé pour demander un nouveau jeton d’accès lorsque le jeton d’origine expire ou devient invalide. Le jeton d’accès est généralement à courte durée de vie et a une date d’expiration beaucoup plus courte que celle du jeton de rafraîchissement.

Lorsque le jeton d’accès expire, l’application peut utiliser le jeton de rafraîchissement pour obtenir un nouveau jeton d’accès auprès du fournisseur d’identité sans exiger de réauthentification de l’utilisateur. Le nouveau jeton d’accès peut ensuite être utilisé pour accéder aux ressources protégées jusqu’à ce qu’il expire ou devienne invalide.

Utiliser l’authentification silencieuse pour gérer les jetons invalides

Une autre solution pour gérer les jetons invalides consiste à utiliser l’authentification silencieuse (également appelée connexion silencieuse ou silent login). Cette méthode permet à l’application de rafraîchir automatiquement le jeton d’accès en arrière-plan sans nécessiter d’interaction de la part de l’utilisateur.

Qu’est-ce que l’authentification silencieuse ?

L’authentification silencieuse est un type de flux qui permet à l’application d’authentifier automatiquement l’utilisateur en arrière-plan sans lui demander de saisir ses identifiants de connexion. Cela est généralement réalisé à l’aide d’un jeton de rafraîchissement ou d’un cookie de session stocké sur l’appareil de l’utilisateur.

Lorsque le jeton d’accès expire ou devient invalide, l’application peut s’appuyer sur le fait que l’utilisateur est toujours authentifié sur le SSO pour obtenir silencieusement un nouveau jeton d’accès en arrière-plan, sans que l’utilisateur n’ait besoin d’interagir avec l’application.

Authentification silencieuse avec le paramètre OIDC “prompt=none”

Lorsqu’on utilise OIDC avec prompt=none, le serveur d’authentification peut vérifier silencieusement si l’utilisateur possède une session active sans lui demander ses identifiants. Voici comment fonctionne le processus :

L’application cliente initie un flux d’autorisation par code avec le paramètre prompt défini sur none. La requête ressemble à ceci :

GET /authorize?client_id=abcd1234&redirect_uri=https://mydomain.com/callback&scope=openid%20profile&response_type=id_token&prompt=none HTTP/1.1
Host: cerberauth.com

Plus d’informations sur ce paramètre sont disponibles dans cet article sur les prompts OpenID Connect.

La réauthentification comme solution

Si ni le rafraîchissement des jetons ni les connexions silencieuses ne sont des solutions viables, la réauthentification est une autre option pour gérer les jetons invalides. Avec cette méthode, l’utilisateur est invité à saisir à nouveau ses identifiants de connexion afin d’obtenir un nouveau jeton d’accès.

Quand utiliser la réauthentification ?

La réauthentification doit être utilisée lorsque le rafraîchissement des jetons et les connexions silencieuses ne sont pas envisageables. Par exemple, si le jeton de rafraîchissement de l’utilisateur a expiré ou si l’utilisateur a révoqué l’accès de l’application, le rafraîchissement du jeton ne sera pas possible. De même, si le cookie de session de l’application a expiré, la connexion silencieuse ne sera pas possible.

Dans ces cas, l’utilisateur doit se réauthentifier afin d’obtenir un nouveau jeton d’accès et continuer à utiliser l’application.

Choisir la bonne solution pour votre application

Lorsqu’il s’agit de gérer les jetons invalides, il n’existe pas de solution unique. La solution appropriée dépendra des besoins et des exigences spécifiques de l’application. Voici quelques facteurs à prendre en compte lors du choix de la solution adaptée à votre application :

Exigences de sécurité

Les exigences de sécurité de l’application joueront un rôle majeur dans la détermination de la solution appropriée pour gérer les jetons invalides. Si l’application traite des données sensibles ou exige un niveau élevé de sécurité, la réauthentification peut être la solution la plus adaptée. À l’inverse, si les données sont moins sensibles et que la priorité est de maintenir une expérience utilisateur fluide, la connexion silencieuse ou le rafraîchissement des jetons peuvent s’avérer plus appropriés.

Expérience utilisateur

L’expérience utilisateur est une considération importante lors du choix d’une solution de gestion des jetons invalides. Les développeurs doivent s’efforcer de minimiser les interruptions de la session utilisateur et de fournir des messages d’erreur clairs et exploitables lorsqu’un jeton d’accès devient invalide.

Technologies disponibles

Les technologies et l’infrastructure disponibles de l’application joueront également un rôle dans la détermination de la solution appropriée. Par exemple, si l’application utilise OpenID Connect ou OAuth, le rafraîchissement des jetons peut s’avérer être la solution la plus simple. Si l’application utilise un mécanisme d’authentification personnalisé, la réauthentification peut être la meilleure option.

Exigences de conformité

Si l’application est soumise à des exigences de conformité telles que HIPAA ou le RGPD, la solution choisie pour gérer les jetons invalides devra se conformer à ces exigences. Par exemple, le RGPD exige que les jetons d’accès aient une durée de vie limitée et que les utilisateurs aient le droit de révoquer leur consentement à tout moment.

En tenant compte de ces facteurs et en évaluant les options disponibles, les développeurs peuvent choisir la solution la plus appropriée pour gérer les jetons invalides dans leurs applications.

Si vous souhaitez tester si votre API gère correctement les jetons invalides, expirés ou révoqués, VulnAPI est un scanner open-source capable de détecter les failles d’authentification cassée, y compris l’absence de validation des jetons.

Conclusion

La gestion des jetons invalides est un aspect critique du développement d’applications web et mobiles sécurisées et ergonomiques. Comme nous l’avons vu, plusieurs solutions s’offrent aux développeurs pour gérer les jetons invalides, telles que le rafraîchissement des jetons, les connexions silencieuses et la réauthentification. Les développeurs doivent choisir la solution la plus appropriée pour leur application spécifique en se basant sur des facteurs tels que les exigences de sécurité, l’expérience utilisateur, les technologies disponibles et les exigences de conformité. De plus, suivre les meilleures pratiques — comme l’utilisation de durées de vie courtes pour les jetons, la surveillance de l’expiration et de la révocation des jetons, la mise en œuvre de la MFA (authentification multifacteur) et la fourniture de messages d’erreur clairs et exploitables — peut contribuer à garantir la sécurité et la continuité des sessions utilisateur.

En mettant en œuvre ces solutions et meilleures pratiques, les développeurs peuvent offrir une expérience utilisateur fluide et sécurisée tout en protégeant les données sensibles de leurs utilisateurs.