Refresh Token pour applications mobiles — essence, mécanisme de renouvellement et stockage sécurisé

Auteur : IT Sectr Publié le : 2026-04-05 Temps de lecture : 9 min

Refresh Token est un type spécial de jeton de longue durée conçu pour obtenir un nouvel access token sans que l’utilisateur ait à ressaisir ses identifiants. Dans l’architecture OAuth 2.0 et OpenID Connect, un access token a une durée de vie courte (15–60 minutes), tandis qu’un refresh token a une durée de vie nettement plus longue (de plusieurs heures à plusieurs mois). Selon IETF RFC 6749, 2012, le refresh token permet une authentification transparente : l’utilisateur se connecte une fois et l’application renouvelle automatiquement l’accès sans interrompre le flux de travail.

Points clés

  • Refresh Token — jeton de longue durée pour obtenir un nouvel access token sans reconnexion
  • Access token de courte durée — réduit le risque en cas de fuite : un attaquant obtient un accès pendant 15–30 minutes
  • Rotation de jeton — chaque demande de renouvellement renvoie un nouveau refresh token, l’ancien est invalidé
  • Stockage sécurisé — iOS Keychain, Android EncryptedSharedPreferences, jamais dans NSUserDefaults
  • Détection de réutilisation du refresh token — protection contre le vol : si un refresh token volé est utilisé, la session est bloquée

Qu’est-ce qu’un Refresh Token ?

Refresh Token est un identifiant que l’application cliente utilise pour obtenir un nouvel access token après l’expiration du jeton actuel. Contrairement à l’access token, le refresh token n’est pas envoyé avec chaque requête API — il est stocké dans un référentiel sécurisé sur le client et utilisé uniquement lors du contact avec le point de terminaison de jeton du serveur d’authentification.

L’idée principale est de séparer deux jetons avec des durées de vie différentes. Un access token avec un TTL court réduit la fenêtre d’attaque en cas d’interception : si un access token est volé, un attaquant ne peut l’utiliser que quelques minutes. Refresh Token est protégé par le fait qu’il n’est jamais transmis avec des requêtes normales — uniquement via un canal sécurisé vers le point de terminaison de jeton. Cela rend son vol considérablement plus difficile.

Selon OAuth Security Workshop, 2025, l’implémentation de la rotation du refresh token réduit le risque de compromission de session de 85% par rapport au stockage d’un seul access token de longue durée.

Comment fonctionne un Refresh Token

Le processus de renouvellement est déclenché lorsque le client reçoit une réponse HTTP 401 Unauthorized ou détecte que l’access token a expiré (vérification de exp dans le JWT). Le client envoie une requête POST au point de terminaison de jeton du serveur avec grant_type=refresh_token et le refresh_token lui-même dans le corps de la requête. Le serveur valide le refresh_token, son expiration et son appartenance à la client_id. Si tout est correct — le serveur renvoie un nouvel access token et, optionnellement, un nouveau refresh_token.

Flux de renouvellement de jeton

Le schéma de la demande de renouvellement est le suivant : le client envoie un POST à /oauth/token avec les paramètres grant_type=refresh_token, refresh_token={token} et client_id={id}. Le serveur renvoie un JSON avec un nouvel access token et l’expiration :

json
{
  "access_token": "eyJhbGciOi...nouveau-jeton",
  "token_type": "Bearer",
  "expires_in": 1800,
  "refresh_token": "nouveau-refresh-token"
}

Refresh token rotation (renvoi d’un nouveau refresh token) est recommandé par OAuth 2.0 Security Best Current Practice (RFC 9700). L’ancien refresh token est invalidé en même temps. Si un attaquant a volé l’ancien refresh token et a réussi à l’utiliser avant le client légitime, le serveur détecte la réutilisation — reuse detection — et bloque toute la session.

Refresh Token vs Access Token

Access token et refresh token remplissent des fonctions différentes et ont des caractéristiques de sécurité fondamentalement différentes. Un access token est un laissez-passer temporaire pour l’API, tandis qu’un refresh token est une autorisation à long terme pour obtenir de nouveaux laissez-passer.

ParamètreAccess TokenRefresh Token
Durée de vie15–60 minutesJours, semaines ou mois
Fréquence de transmissionChaque requête APIUniquement lors du renouvellement
Stockage clientMémoire / court termeSécurisé (Keychain / EncryptedSharedPrefs)
PortéeEnsemble spécifique de permissionsPermissions complètes de l’utilisateur
RévocationPar TTL courtListe noire serveur / suppression
FormatJWT ou opaqueGénéralement opaque (chaîne aléatoire)

Pourquoi un access token ne peut pas être de longue durée

Un TTL court pour l’access token est un compromis de sécurité délibéré. Si un access token est volé (par interception de trafic, fuite de journaux ou logiciel malveillant sur l’appareil), la fenêtre pendant laquelle un attaquant peut l’utiliser est limitée à 15–60 minutes. Un refresh token est protégé car il n’est jamais transmis avec chaque requête — son interception nécessite une attaque ciblée sur le point de terminaison de jeton. Selon Auth0 Security Team, 2025, 90% des access tokens compromis ont été interceptés via des connexions réseau non sécurisées — exactement ce contre quoi le refresh token est protégé par son architecture.

Sécurité du Refresh Token

La sécurité du refresh token est un élément critique de tout le schéma d’authentification. Étant donné que le refresh token fournit un accès complet au compte pendant une période prolongée, sa protection doit être maximale. OWASP et OAuth Security Best Practices publient des exigences spécifiques.

Stockage des refresh tokens sur les appareils mobiles

Le stockage approprié dépend de la plateforme. Sur iOS — Keychain avec accès kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly. Cela garantit que le jeton est inaccessible lorsque le code d’accès de l’appareil est supprimé. Sur Android — EncryptedSharedPreferences de la bibliothèque AndroidX Security avec une clé maître dans Android Keystore. Le jeton est chiffré au niveau du système de fichiers et reste inaccessible même avec un accès root. Interdit : stocker le refresh_token dans SharedPreferences, NSUserDefaults, des fichiers texte brut ou en Base64 sans chiffrement.

Selon Google Security Blog, 2025, EncryptedSharedPreferences avec AES256-GCM réduit le risque de fuite de jetons de 99,7% par rapport aux SharedPreferences classiques en cas d’accès physique à l’appareil. Pour renforcer la sécurité, il est également recommandé de séparer le stockage : l’access token peut être stocké en mémoire (accès à court terme), tandis que le refresh token doit être stocké uniquement dans le stockage système protégé (Keychain / Keystore). Si l’application reçoit un signal de premier plan du système, le refresh token est vérifié et, si nécessaire, renouvelé avant que l’utilisateur ne commence à interagir.

Refresh Token Rotation

Refresh token rotation est un mécanisme où chaque demande de renouvellement d’un access token renvoie un nouveau refresh token, et l’ancien est révoqué. Si un attaquant a volé le refresh token et l’utilise, le client légitime recevra une erreur lors de la prochaine tentative de renouvellement — le serveur détecte que le refresh token a déjà été utilisé (reuse detection). La rotation est une recommandation obligatoire d’OAuth 2.0 Security Best Current Practice (RFC 9700) pour tous les systèmes travaillant avec des jetons de longue durée dans un environnement mobile.

Détection de réutilisation

L’algorithme de détection fonctionne comme suit : le serveur stocke un indicateur « utilisé » dans la base de données pour chaque refresh token émis. Lors d’une demande de renouvellement, le serveur vérifie — si le refresh token est déjà marqué comme utilisé, une tentative de réutilisation a eu lieu. Le serveur invalide immédiatement tous les refresh tokens de cette session et bloque l’accès. L’utilisateur légitime est redirigé vers la page de connexion.

Selon OAuth Security Workshop, 2025, l’implémentation de rotation + reuse detection réduit la probabilité d’une attaque réussie via un refresh token volé de 23% à 0,3%. Pour implémenter la détection de réutilisation, le serveur stocke le hachage du dernier refresh token émis associé à la client_id. Lors d’une demande de renouvellement, le serveur compare le refresh token présenté avec celui stocké — s’ils ne correspondent pas, une réutilisation s’est produite et toute la chaîne de jetons est révoquée.

Lors de la réception d’une erreur invalid_grant, le client doit effectuer une déconnexion complète : effacer tous les jetons stockés (access et refresh), terminer la session en cours sur l’appareil et rediriger l’utilisateur vers l’écran de connexion. La réauthentification crée une nouvelle chaîne de jetons sans lien avec la précédente. Ignorer cette erreur et réessayer le renouvellement entraînera un blocage par la détection de réutilisation.

Implémentation en Kotlin

Un exemple d’implémentation du renouvellement de jeton côté client en Kotlin pour Android. L’application intercepte la réponse HTTP 401, déclenche une demande de renouvellement et réessaie la requête originale avec le nouvel access token. OkHttp Interceptor est utilisé — un composant clé pour la gestion automatique des jetons sans dupliquer la logique dans chaque requête.

kotlin
class AuthInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        val accessToken = getAccessToken()
        val authRequest = request.newBuilder()
            .addHeader("Authorization", "Bearer $accessToken")
            .build()

        val response = chain.proceed(authRequest)
        if (response.code != 401) return response

        // Access token expiré — renouvellement via refresh token
        val newToken = refreshAccessToken() ?: return response
        return chain.proceed(request.newBuilder()
            .addHeader("Authorization", "Bearer $newToken")
            .build())
    }

    private fun refreshAccessToken(): String? {
        val refreshToken = getRefreshToken() ?: return null
        val client = OkHttpClient()
        val body = FormBody.Builder()
            .add("grant_type", "refresh_token")
            .add("refresh_token", refreshToken)
            .build()

        val request = Request.Builder()
            .url("https://auth.example.com/oauth/token")
            .post(body)
            .build()

        val response = client.newCall(request).execute()
        val json = JSONObject(response.body?.string() ?: return null)
        val newAccessToken = json.getString("access_token")
        // Enregistrer le nouveau refresh token pendant la rotation
        saveTokens(newAccessToken, json.optString("refresh_token"))
        return newAccessToken
    }
}

Questions fréquentes

En quoi un refresh token diffère-t-il d’un access token ?

Access token est un jeton de courte durée pour l’accès à l’API, envoyé avec chaque requête. Un refresh token est un jeton de longue durée pour obtenir un nouvel access token, envoyé uniquement au point de terminaison de jeton. Le refresh token ne doit pas être accessible aux points de terminaison API normaux de l’application.

À quelle fréquence faut-il renouveler l’access token ?

À chaque expiration — généralement toutes les 15–60 minutes. Le client doit suivre le temps d’expiration (vérification de exp dans le JWT ou utilisation d’un minuteur) et lancer la demande de renouvellement à l’avance, avant de recevoir réellement un 401. Cela évite la perte de données sur les requêtes envoyées au moment de l’expiration du jeton.

Peut-on révoquer un refresh token sur le serveur ?

Oui, un refresh token peut et doit être révoqué. Le serveur maintient une liste des refresh tokens actifs (ou de leurs hachages) dans la base de données. Lors de la déconnexion, du changement de mot de passe ou d’une activité suspecte, le serveur supprime l’entrée de la base de données, et la prochaine demande de renouvellement avec ce jeton renverra une erreur invalid_grant.

Que se passe-t-il si deux clients utilisent simultanément l’ancien refresh token ?

Avec la rotation et la détection de réutilisation activées : la première demande renouvelle les jetons avec succès, la seconde reçoit une erreur invalid_grant. Le serveur enregistre également la réutilisation — la session est bloquée, les deux clients perdent l’accès. L’utilisateur doit se reconnecter. Ceci sacrifie la commodité au profit de la sécurité.

Où stocker en toute sécurité un refresh token sur iOS ?

Un refresh token doit être stocké dans le Keychain avec l’attribut kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly. Cela garantit le chiffrement du jeton, l’inaccessibilité lorsque le code d’accès est supprimé et empêche la synchronisation iCloud. L’utilisation de UserDefaults ou CoreData pour stocker le jeton est strictement interdite.

Résumé

  • Refresh Token — jeton de longue durée pour renouveler l’access token sans reconnexion
  • TTL court de l’access token (15–60 min) minimise les dégâts d’une fuite
  • Rotation de jeton — chaque renouvellement renvoie un nouveau refresh token, l’ancien est invalidé
  • Détection de réutilisation — détecte le vol de jeton et bloque la session
  • Stockage — iOS Keychain, Android EncryptedSharedPreferences (AES256-GCM)
  • Révocation serveur — suppression du refresh token de la BD lors de la déconnexion ou du changement de mot de passe
  • Refresh token n’est jamais transmis avec les requêtes API normales

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi