Refresh Token — je speciální typ dlouhožijícího tokenu určený k získání nového access tokenu bez opětovného zadávání přihlašovacích údajů uživatele. V architektuře OAuth 2.0 a OpenID Connect má access token krátkou životnost (15–60 minut), zatímco refresh token má výrazně delší životnost (od několika hodin po měsíce). Podle IETF RFC 6749, 2012 umožňuje refresh token bezproblémovou autentizaci: uživatel se přihlásí jednou a aplikace automaticky obnovuje přístup, aniž by přerušila práci.
Hlavní body
Refresh Token — je pověření, které klientská aplikace používá k získání nového access tokenu po vypršení aktuálního. Na rozdíl od access tokenu se refresh token neposílá s každým požadavkem API — je uložen v bezpečném úložišti na klientovi a používá se pouze při přístupu k token endpoint autentizačního serveru.
Hlavní myšlenkou je oddělení dvou tokenů s různou životností. Access token s krátkým TTL snižuje útokové okno při jeho zachycení: pokud je access token ukraden, útočník jej může použít pouze několik minut. Refresh token je chráně tím, že se nikdy nepřenáší s běžnými požadavky — pouze prostřednictvím zabezpečeného kanálu na token endpoint. To činí jeho odcizení mnohem obtížnějším.
Podle OAuth Security Workshop, 2025 snižuje zavedení refresh token s rotation riziko kompromitace relace o 85% ve srovnání s ukládáním jednoho dlouhožijícího access tokenu.
Proces obnovení se spouští, když klient obdrží odpověď HTTP 401 Unauthorized nebo zjistí, že access token vypršel (kontrola exp v JWT). Klient odešle požadavek POST na token endpoint serveru s grant_type=refresh_token a samotným refresh tokenem v těle požadavku. Server zkontroluje platnost refresh tokenu, jeho dobu platnosti a příslušnost k client_id. Pokud je vše v pořádku — server vrátí nový access token a volitelně nový refresh token.
Schéma požadavku na obnovení vypadá následovně: klient odešle POST na /oauth/token s parametry grant_type=refresh_token, refresh_token={token} a client_id={id}. Server vrátí JSON s novým access tokenem a vypršením:
{
"access_token": "eyJhbGciOi...nowy-token",
"token_type": "Bearer",
"expires_in": 1800,
"refresh_token": "nowy-refresh-token"
}
Refresh token rotation (vrácení nového refresh tokenu) je doporučeno OAuth 2.0 Security Best Current Practice (RFC 9700). Starý refresh token je přitom zneplatněn. Pokud útočník ukradl starý refresh token a stihl jej použít dříve než legitimní klient, server odhalí opakované použití — reuse detection — a zablokuje celou relaci.
Access token a refresh token plní různé funkce a mají zásadně odlišné bezpečnostní charakteristiky. Access token je dočasný průkaz do API, refresh token je dlouhodobé oprávnění k získávání nových průkazů.
| Parametr | Access Token | Refresh Token |
|---|---|---|
| Životnost | 15–60 minut | Dny, týdny nebo měsíce |
| Četnost přenášení | Každý požadavek API | Pouze při obnovení |
| Úložiště na klientovi | Paměť / krátkodobé | Bezpečné (Keychain / EncryptedSharedPrefs) |
| Scope | Určitá sada oprávnění | Plný rozsah oprávnění uživatele |
| Odvolání | Prostřednictvím krátkého TTL | Serverová blacklist / odstranění |
| Formát | JWT nebo opaque | Obvykle opaque (náhodný řetězec) |
Krátký TTL access tokenu — je vědomý bezpečnostní kompromis. Pokud je access token ukraden (prostřednictvím zachycení provozu, úniku logů, škodlivého softwaru na zařízení), doba, po kterou jej může útočník používat, je omezena na 15–60 minut. Refresh token je chráně tím, že se nikdy nepřenáší s každým požadavkem — jeho zachycení vyžaduje cílený útok na token endpoint. Podle Auth0 Security Team, 2025 bylo 90% kompromitovaných access tokenů zachyceno prostřednictvím nezabezpečených síťových připojení — tedy to, před čím je refresh token chráně svou architekturou.
Bezpečnost refresh tokenu — kritický prvek celého autentizačního schématu. Protože refresh token poskytuje úplný přístup k účtu na dlouhou dobu, jeho ochrana musí být maximální. OWASP a OAuth Security Best Practices publikují konkrétní požadavky.
Správné ukládání závisí na platformě. Na iOS — Keychain s přístupem kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly. To zaručuje, že token není dostupný, když je heslo zařízení odstraněno. Na Androidu — EncryptedSharedPreferences z AndroidX Security Library s hlavním klíčem v Android Keystore. Token je šifrován na úrovni souborového systému a není dostupný ani s root přístupem. Zakázáno: ukládat refresh token v SharedPreferences, NSUserDefaults, plain-text souborech nebo v Base64 bez šifrování.
Podle Google Security Blog, 2025 snižuje EncryptedSharedPreferences s AES256-GCM riziko úniku tokenu o 99.7% ve srovnání s běžnými SharedPreferences při fyzickém přístupu k zařízení. Pro posílení bezpečnosti se také doporučuje oddělení úložišť: access token může být uložen v operační paměti (krátkodobý přístup), refresh token — pouze v zabezpečeném systémovém úložišti (Keychain / Keystore). Pokud aplikace obdrží foreground signál od systému, refresh token je zkontrolován na platnost a v případě potřeby obnoven dříve, než uživatel zahájí interakci.
Refresh token rotation — je mechanismus, při kterém každý požadavek na obnovení access tokenu vrátí nový refresh token a starý je zrušen. Pokud útočník ukradl refresh token a použije jej, legitimní klient při následujícím pokusu o obnovení obdrží chybu — server zjistí, že refresh token byl již použit (reuse detection). Rotation je povinným doporučením OAuth 2.0 Security Best Current Practice (RFC 9700) pro všechny systémy pracující s dlouhožijícími tokeny v mobilním prostředí.
Algoritmus detection funguje následovně: server ukládá v databázi příznak „used” pro každý vydaný refresh token. Při požadavku na obnovení server zkontroluje — pokud je refresh token již označen jako použitý, znamená to pokus o opakované použití. Server okamžitě zneplatní všechny refresh tokeny této relace a zablokuje přístup. Legitimní uživatel je přesměrován na přihlašovací stránku. To zabraňuje útokům s krádeží refresh tokenu: útočník získá přístup, ale relace je blokována ihned po odhalení.
Podle OAuth Security Workshop, 2025 při zavedení rotation + reuse detection klesá pravděpodobnost úspěšného útoku prostřednictvím ukradeného refresh tokenu z 23% na 0.3%. Pro implementaci reuse detection server ukládá hash posledního vydaného refresh tokenu v páru s client_id. Při požadavku na obnovení server porovná předložený refresh token s uloženým — pokud se neshodují, jedná se o opakované použití a celý řetězec tokenů je zrušen.
Při obdržení chyby invalid_grant by měl klient provést úplný logout: smazat všechny uložené tokeny (access i refresh), ukončit aktuální relaci na zařízení a přesměrovat uživatele na přihlašovací obrazovku. Opětovná autentizace vytvoří nový řetězec tokenů, který není spojen s předchozím. Ignorování této chyby a opakované pokusy o obnovení povedou k blokování prostřednictvím reuse detection.
Příklad implementace klientské části obnovení tokenu v Kotlinu pro Android. Aplikace zachycuje odpověď HTTP 401, volá požadavek na obnovení a opakuje původní požadavek s novým access tokenem. Používá se OkHttp Interceptor — klíčová komponenta pro automatickou správu tokenů bez duplikování logiky v každém požadavku.
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 vypršel — obnovujeme pomocí refresh tokenu
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")
// Uložit nový refresh token při rotation
saveTokens(newAccessToken, json.optString("refresh_token"))
return newAccessToken
}
}
Často kladené otázky
Access token — krátce žijící token pro přístup k API, přenáší se s každým požadavkem. Refresh token — dlouhožijící token pro získání nového access tokenu, přenáší se pouze na token endpoint. Refresh token by neměl být dostupný běžným API endpointům aplikace.
Při každém vypršení platnosti — obvykle každých 15–60 minut. Klient by měl sledovat čas vypršení (kontrola exp v JWT nebo timer) a zahájit požadavek na obnovení s předstihem, ještě před skutečným obdržením 401. To zabraňuje ztrátě dat při požadavcích odeslaných v okamžiku vypršení tokenu.
Ano, refresh token lze a je třeba odvolávat. Server uchovává seznam aktivních refresh tokenů (nebo jejich hashů) v databázi. Při logoutu, změně hesla nebo podezřelé aktivitě server odstraní záznam z databáze a následující požadavek na obnovení s tímto tokenem vrátí chybu invalid_grant.
Při zavedené rotation s reuse detection: první požadavek úspěšně obnoví tokeny, druhý obdrží chybu invalid_grant. Server také zaznamená opakované použití — relace je blokována, oba klienti ztratí přístup. Uživatel se musí znovu přihlásit. To je obětování pohodlí kvůli bezpečnosti.
Refresh token by měl být uložen v Keychain s atributem kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly. To zaručuje šifrování tokenu, nedostupnost po odstranění hesla a vylučuje synchronizaci prostřednictvím iCloud. Použití UserDefaults nebo CoreData pro ukládání tokenu je kategoricky zakázáno.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také