Refresh Token — este un tip special de token de lungă durată, destinat obținerii unui nou access token fără reintroducerea datelor de autentificare ale utilizatorului. În arhitectura OAuth 2.0 și OpenID Connect, access token are o durată scurtă de viață (15–60 de minute), iar refresh token — semnificativ mai lungă (de la câteva ore la luni). Conform IETF RFC 6749, 2012, refresh token permite implementarea autentificării fără întreruperi: utilizatorul se autentifică o singură dată, iar aplicația reîmprospătează automat accesul fără a întrerupe activitatea.
Elemente principale
Refresh Token — este o credențială pe care aplicația client o folosește pentru a obține un nou access token după expirarea celui curent. Spre deosebire de access token, refresh token nu este trimis cu fiecare cerere API — este stocat într-un depozit sigur pe client și utilizat doar la accesarea token endpoint a serverului de autentificare.
Ideea principală este separarea a două tokenuri cu durate de viață diferite. Access token cu TTL scurt reduce fereastra de atac la interceptarea sa: dacă access token este furat, atacatorul îl poate folosi doar câteva minute. Refresh token este protejat de faptul că nu este transmis niciodată cu cererile obișnuite — doar printr-un canal securizat către token endpoint. Acest lucru face furtul său mult mai dificil.
Conform OAuth Security Workshop, 2025, implementarea refresh token cu rotation reduce riscul de compromitere a sesiunii cu 85% comparativ cu stocarea unui singur access token de lungă durată.
Procesul de reîmprospătare este declanșat atunci când clientul primește un răspuns HTTP 401 Unauthorized sau detectează că access token a expirat (verificarea exp în JWT). Clientul trimite o cerere POST la token endpoint a serverului cu grant_type=refresh_token și refresh token în corpul cererii. Serverul verifică validitatea refresh token, termenul său de expirare și apartenența la client_id. Dacă totul este corect — serverul returnează un nou access token și, opțional, un nou refresh token.
Schema cererii de reîmprospătare arată astfel: clientul trimite un POST la /oauth/token cu parametrii grant_type=refresh_token, refresh_token={token} și client_id={id}. Serverul returnează un JSON cu noul access token și expirarea:
{
"access_token": "eyJhbGciOi...nowy-token",
"token_type": "Bearer",
"expires_in": 1800,
"refresh_token": "nowy-refresh-token"
}
Refresh token rotation (returnarea unui nou refresh token) este recomandat de OAuth 2.0 Security Best Current Practice (RFC 9700). Refresh tokenul vechi este invalidat în acest proces. Dacă un atacator a furat refresh tokenul vechi și a reușit să îl folosească înaintea clientului legitim, serverul va detecta utilizarea repetată — reuse detection — și va bloca întreaga sesiune.
Access token și refresh token îndeplinesc funcții diferite și au caracteristici de securitate fundamental diferite. Access token este un permis temporar pentru API, refresh token este o autorizație pe termen lung pentru obținerea de noi permise.
| Parametru | Access Token | Refresh Token |
|---|---|---|
| Durata de viață | 15–60 de minute | Zile, săptămâni sau luni |
| Frecvența transmiterii | Fiecare cerere API | Doar la reîmprospătare |
| Depozit pe client | Memorie / termen scurt | Sigur (Keychain / EncryptedSharedPrefs) |
| Scope | Set specific de permisiuni | Volumul complet de permisiuni al utilizatorului |
| Revocare | Prin TTL scurt | Blacklist pe server / ștergere |
| Format | JWT sau opaque | De obicei opaque (șir aleator) |
TTL scurt al access token — este un compromis conștient de securitate. Dacă access token este furat (prin interceptarea traficului, scurgerea jurnalelor, software malițios pe dispozitiv), timpul în care atacatorul îl poate folosi este limitat la 15–60 de minute. Refresh token este protejat de faptul că nu este transmis la fiecare cerere — interceptarea sa necesită un atac direcționat asupra token endpoint. Conform Auth0 Security Team, 2025, 90% din access tokenurile compromise au fost interceptate prin conexiuni de rețea nesecurizate — exact ceea ce refresh token este protejat prin arhitectura sa.
Securitatea refresh token — element critic al întregii scheme de autentificare. Deoarece refresh token oferă acces complet la cont pentru o perioadă lungă, protecția sa trebuie să fie maximă. OWASP și OAuth Security Best Practices publică cerințe specifice.
Stocarea corectă depinde de platformă. Pe iOS — Keychain cu acces kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly. Aceasta garantează că tokenul nu este disponibil atunci când parola dispozitivului este eliminată. Pe Android — EncryptedSharedPreferences din AndroidX Security Library cu cheia principală în Android Keystore. Tokenul este criptat la nivelul sistemului de fișiere și indisponibil chiar și cu acces root. Interzis: stocarea refresh token în SharedPreferences, NSUserDefaults, fișiere plain-text sau în Base64 fără criptare.
Conform Google Security Blog, 2025, EncryptedSharedPreferences cu AES256-GCM reduc riscul de scurgere a tokenurilor cu 99.7% comparativ cu SharedPreferences obișnuite la acces fizic la dispozitiv. Pentru întărirea securității, se recomandă, de asemenea, separarea depozitelor: access token poate fi stocat în memoria operativă (acces pe termen scurt), refresh token — doar în depozitul securizat de sistem (Keychain / Keystore). Dacă aplicația primește un semnal foreground de la sistem, refresh token este verificat pentru validitate și, dacă este necesar, reîmprospătat înainte ca utilizatorul să înceapă interacțiunea.
Refresh token rotation — este un mecanism prin care fiecare cerere de reîmprospătare a access token returnează un nou refresh token, iar cel vechi este anulat. Dacă un atacator a furat refresh token și îl folosește, clientul legitim va primi o eroare la următoarea încercare de reîmprospătare — serverul va detecta că refresh token a fost deja folosit (reuse detection). Rotation este o recomandare obligatorie OAuth 2.0 Security Best Current Practice (RFC 9700) pentru toate sistemele care lucrează cu tokenuri de lungă durată în mediul mobil.
Algoritmul de detection funcționează astfel: serverul stochează în bază un indicator „used” pentru fiecare refresh token emis. La cererea de reîmprospătare, serverul verifică — dacă refresh token este deja marcat ca utilizat, înseamnă că a avut loc o încercare de utilizare repetată. Serverul invalidează imediat toate refresh tokenurile acestei sesiuni și blochează accesul. Utilizatorul legitim este redirecționat către pagina de autentificare. Acest lucru previne atacurile cu furt de refresh token: atacatorul obține acces, dar sesiunea este blocată imediat după detectare.
Conform OAuth Security Workshop, 2025, la implementarea rotation + reuse detection, probabilitatea unui atac reușit prin refresh token furat scade de la 23% la 0.3%. Pentru implementarea reuse detection, serverul stochează hash-ul ultimului refresh token emis împreună cu client_id. La cererea de reîmprospătare, serverul compară refresh tokenul prezentat cu cel stocat — dacă nu coincid, înseamnă utilizare repetată și întregul lanț de tokenuri este anulat.
La primirea erorii invalid_grant, clientul trebuie să execute un logout complet: să șteargă toate tokenurile salvate (access și refresh), să încheie sesiunea curentă pe dispozitiv și să redirecționeze utilizatorul către ecranul de autentificare. Reautentificarea creează un nou lanț de tokenuri, fără legătură cu cel anterior. Ignorarea acestei erori și încercările repetate de refresh vor duce la blocarea prin reuse detection.
Exemplu de implementare a părții client de reîmprospătare a tokenului în Kotlin pentru Android. Aplicația interceptează răspunsul HTTP 401, trimite o cerere de reîmprospătare și repetă cererea originală cu noul access token. Se folosește OkHttp Interceptor — o componentă cheie pentru gestionarea automată a tokenurilor fără duplicarea logicii în fiecare cerere.
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 a expirat — reîmprospătăm prin 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")
// Salvează noul refresh token la rotation
saveTokens(newAccessToken, json.optString("refresh_token"))
return newAccessToken
}
}
Întrebări frecvente
Access token — token de scurtă durată pentru accesul la API, transmis cu fiecare cerere. Refresh token — token de lungă durată pentru obținerea unui nou access token, transmis doar la token endpoint. Refresh token nu trebuie să fie disponibil pentru endpointurile obișnuite ale aplicației.
La fiecare expirare — de obicei la fiecare 15–60 de minute. Clientul trebuie să monitorizeze timpul de expirare (verificarea exp în JWT sau un timer) și să inițieze cererea de reîmprospătare în avans, înainte de a primi efectiv 401. Acest lucru previne pierderea datelor la cererile trimise în momentul expirării tokenului.
Da, refresh token poate și trebuie revocat. Serverul păstrează o listă de refresh tokenuri active (sau hashurile lor) în baza de date. La logout, schimbarea parolei sau activitate suspectă, serverul șterge înregistrarea din baza de date, iar următoarea cerere de reîmprospătare cu acest token va returna eroarea invalid_grant.
Cu rotation și reuse detection implementate: prima cerere reîmprospătează cu succes tokenurile, a doua primește eroarea invalid_grant. Serverul înregistrează și utilizarea repetată — sesiunea este blocată, ambii clienți pierd accesul. Utilizatorul trebuie să se autentifice din nou. Acesta este un sacrificiu al confortului pentru securitate.
Refresh token trebuie stocat în Keychain cu atributul kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly. Aceasta garantează criptarea tokenului, indisponibilitatea la eliminarea parolei și exclude sincronizarea prin iCloud. Utilizarea UserDefaults sau CoreData pentru stocarea tokenului este categoric interzisă.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și