Refresh Token dla aplikacji mobilnych — istota, mechanizm odświeżania i bezpieczne przechowywanie

Autor: IT Sectr Opublikowano: 2026-04-05 Czas czytania: 9 min

Refresh Token — to specjalny typ długożyjącego tokena, przeznaczony do uzyskania nowego access token bez ponownego wprowadzania danych uwierzytelniających użytkownika. W architekturze OAuth 2.0 i OpenID Connect access token ma krótki czas życia (15–60 minut), a refresh token — znacznie dłuższy (od kilku godzin do miesięcy). Według danych IETF RFC 6749, 2012, refresh token pozwala zrealizować bezproblemowe uwierzytelnianie: użytkownik loguje się raz, a aplikacja automatycznie odświeża dostęp, nie przerywając pracy.

Najważniejsze

  • Refresh Token — długożyjący token do uzyskania nowego access token bez re-login
  • Krótki access token — zmniejsza ryzyko przy wycieku: atakujący uzyskuje dostęp na 15–30 minut
  • Token rotation — każde żądanie odświeżenia zwraca nowy refresh token, stary jest unieważniany
  • Bezpieczne przechowywanie — iOS Keychain, Android EncryptedSharedPreferences, nigdy w NSUserDefaults
  • Refresh token reuse detection — ochrona przed kradzieżą: jeśli skradziony refresh token został użyty, sesja jest blokowana

Co to jest Refresh Token?

Refresh Token — to dane uwierzytelniające, które aplikacja kliencka wykorzystuje do uzyskania nowego access token po wygaśnięciu bieżącego. W przeciwieństwie do access token, refresh token nie jest wysyłany z każdym żądaniem API — przechowuje się go w bezpiecznym magazynie na kliencie i używa tylko przy odwołaniu do token endpoint serwera uwierzytelniania.

Główną ideą jest rozdzielenie dwóch tokenów o różnym czasie życia. Access token z krótkim TTL zmniejsza okno ataku przy jego przechwyceniu: jeśli access token zostanie skradziony, atakujący może go używać tylko przez kilka minut. Refresh token jest chroniony przez to, że nigdy nie jest przesyłany ze zwykłymi żądaniami — tylko przez zabezpieczony kanał do token endpoint. To sprawia, że jego kradzież jest znacznie trudniejsza.

Według danych OAuth Security Workshop, 2025, wdrożenie refresh token z rotation zmniejsza ryzyko kompromitacji sesji o 85% w porównaniu z przechowywaniem jednego długożyjącego access token.

Jak działa Refresh Token

Proces odświeżania uruchamiany jest, gdy klient otrzymuje odpowiedź HTTP 401 Unauthorized lub wykrywa, że access token wygasł (sprawdzenie exp w JWT). Klient wysyła żądanie POST do token endpoint serwera z grant_type=refresh_token i samym refresh token w treści żądania. Serwer sprawdza ważność refresh token, jego termin ważności i przynależność do client_id. Jeśli wszystko jest poprawne — serwer zwraca nowy access token i opcjonalnie nowy refresh token.

Przebieg odświeżania tokena

Schemat żądania odświeżenia wygląda następująco: klient wysyła POST na /oauth/token z parametrami grant_type=refresh_token, refresh_token={token} i client_id={id}. Serwer zwraca JSON z nowym access token i wygaśnięciem:

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

Refresh token rotation (zwrot nowego refresh token) jest zalecany przez OAuth 2.0 Security Best Current Practice (RFC 9700). Stary refresh token przy tym jest unieważniany. Jeśli atakujący ukradł stary refresh token i zdążył go użyć przed legalnym klientem, serwer wykryje ponowne użycie — reuse detection — i zablokuje całą sesję.

Refresh Token vs Access Token

Access token i refresh token pełnią różne funkcje i mają zasadniczo różne charakterystyki bezpieczeństwa. Access token to tymczasowa przepustka do API, refresh token to długoterminowe zezwolenie na otrzymywanie nowych przepustek.

ParametrAccess TokenRefresh Token
Czas życia15–60 minutDni, tygodnie lub miesiące
Częstotliwość przesyłaniaKażde żądanie APITylko przy odświeżaniu
Magazyn na klienciePamięć / krótkoterminoweBezpieczne (Keychain / EncryptedSharedPrefs)
ScopeOkreślony zestaw uprawnieńPełen zakres uprawnień użytkownika
OdwołaniePrzez krótki TTLSerwerowa blacklist / usunięcie
FormatJWT lub opaqueZazwyczaj opaque (losowy ciąg)

Dlaczego access token nie może być długożyjący

Krótki TTL access token — to świadomy kompromis bezpieczeństwa. Jeśli access token zostanie skradziony (przez przechwycenie ruchu, wyciek logów, złośliwe oprogramowanie na urządzeniu), czas, w którym atakujący może go używać, jest ograniczony do 15–60 minut. Refresh token jest chroniony przez to, że nigdy nie jest przesyłany przy każdym żądaniu — jego przechwycenie wymaga ukierunkowanego ataku na token endpoint. Według danych Auth0 Security Team, 2025, 90% skompromitowanych access token zostało przechwyconych przez niezabezpieczone połączenia sieciowe — czyli to, przed czym refresh token jest chroniony samą architekturą.

Bezpieczeństwo Refresh Token

Bezpieczeństwo refresh token — krytyczny element całego schematu uwierzytelniania. Ponieważ refresh token zapewnia pełny dostęp do konta na długi okres, jego ochrona musi być maksymalna. OWASP i OAuth Security Best Practices publikują konkretne wymagania.

Przechowywanie refresh token na urządzeniach mobilnych

Prawidłowe przechowywanie zależy od platformy. Na iOS — Keychain z dostępem kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly. To gwarantuje, że token jest niedostępny przy zdjętym haśle urządzenia. Na Android — EncryptedSharedPreferences z AndroidX Security Library z kluczem głównym w Android Keystore. Token jest szyfrowany na poziomie systemu plików i niedostępny nawet przy root-dostępie. Zabronione: przechowywanie refresh token w SharedPreferences, NSUserDefaults, plikach plain-text lub w Base64 bez szyfrowania.

Według danych Google Security Blog, 2025, EncryptedSharedPreferences z AES256-GCM zmniejszają ryzyko wycieku tokenów o 99.7% w porównaniu ze zwykłymi SharedPreferences przy fizycznym dostępie do urządzenia. Dla wzmocnienia bezpieczeństwa zaleca się również rozdzielenie magazynów: access token może być przechowywany w pamięci operacyjnej (krótkoterminowy dostęp), refresh token — tylko w zabezpieczonym magazynie systemowym (Keychain / Keystore). Jeśli aplikacja otrzymuje sygnał foreground od systemu, refresh token jest sprawdzany pod kątem ważności i w razie potrzeby odświeżany zanim użytkownik zacznie interakcję.

Refresh Token Rotation

Refresh token rotation — to mechanizm, przy którym każde żądanie odświeżenia access token zwraca nowy refresh token, a stary jest unieważniany. Jeśli atakujący ukradł refresh token i go użyje, legalny klient przy następnej próbie odświeżenia otrzyma błąd — serwer wykryje, że refresh token został już użyty (reuse detection). Rotation jest obowiązkowym zaleceniem OAuth 2.0 Security Best Current Practice (RFC 9700) dla wszystkich systemów pracujących z długożyjącymi tokenami w środowisku mobilnym.

Reuse Detection

Algorytm detection działa następująco: serwer przechowuje w bazie znacznik „used” dla każdego wydanego refresh token. Przy żądaniu odświeżenia serwer sprawdza — jeśli refresh token jest już oznaczony jako użyty, oznacza to próbę ponownego użycia. Serwer natychmiast unieważnia wszystkie refresh token danej sesji i blokuje dostęp. Legalny użytkownik jest przekierowywany na stronę logowania. Zapobiega to atakom z kradzieżą refresh token: atakujący uzyskuje dostęp, ale sesja jest blokowana natychmiast po wykryciu.

Według danych OAuth Security Workshop, 2025, przy wdrożeniu rotation + reuse detection prawdopodobieństwo udanego ataku przez skradziony refresh token spada z 23% do 0.3%. Dla implementacji reuse detection serwer przechowuje hash ostatniego wydanego refresh token w parze z client_id. Przy żądaniu odświeżenia serwer porównuje przedstawiony refresh token z zapisanym — jeśli nie są zgodne, oznacza to ponowne użycie i cały łańcuch tokenów jest unieważniany.

Po otrzymaniu błędu invalid_grant klient powinien wykonać pełny logout: wyczyścić wszystkie zapisane tokeny (access i refresh), zakończyć bieżącą sesję na urządzeniu i przekierować użytkownika na ekran logowania. Ponowne uwierzytelnienie tworzy nowy łańcuch tokenów, niezwiązany z poprzednim. Ignorowanie tego błędu i ponowne próby refresh doprowadzą do blokady przez reuse detection.

Implementacja w Kotlin

Przykład implementacji części klienckiej odświeżania tokena w Kotlin dla Android. Aplikacja przechwytuje odpowiedź HTTP 401, wywołuje żądanie refresh i powtarza oryginalne żądanie z nowym access token. Używany jest OkHttp Interceptor — kluczowy komponent do automatycznego zarządzania tokenami bez duplikowania logiki w każdym żądaniu.

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 wygasł — odświeżamy przez 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")
        // Zapisz nowy refresh token przy rotation
        saveTokens(newAccessToken, json.optString("refresh_token"))
        return newAccessToken
    }
}

Często zadawane pytania

Czym refresh token różni się od access token?

Access token — krótkożyjący token do dostępu do API, przesyłany z każdym żądaniem. Refresh token — długożyjący token do uzyskania nowego access token, przesyłany tylko do token endpoint. Refresh token nie powinien być dostępny dla zwykłych endpointów API aplikacji.

Jak często należy odświeżać access token?

Przy każdym wygaśnięciu terminu — zazwyczaj co 15–60 minut. Klient powinien śledzić czas wygaśnięcia (sprawdzenie exp w JWT lub timer) i inicjować żądanie refresh z wyprzedzeniem, przed faktycznym otrzymaniem 401. Zapobiega to utracie danych przy żądaniach wysłanych w momencie wygaśnięcia tokena.

Czy można odwołać refresh token na serwerze?

Tak, refresh token można i należy odwoływać. Serwer przechowuje listę aktywnych refresh token (lub ich hash) w bazie danych. Przy logout, zmianie hasła lub podejrzanej aktywności serwer usuwa wpis z bazy danych, a następne żądanie odświeżenia z tym tokenem zwróci błąd invalid_grant.

Co się stanie przy jednoczesnym użyciu starego refresh token przez dwóch klientów?

Przy wdrożonym rotation z reuse detection: pierwsze żądanie pomyślnie odświeża tokeny, drugie otrzymuje błąd invalid_grant. Serwer również rejestruje ponowne użycie — sesja zostaje zablokowana, obaj klienci tracą dostęp. Użytkownik musi zalogować się ponownie. Jest to poświęcenie wygody na rzecz bezpieczeństwa.

Gdzie bezpiecznie przechowywać refresh token w iOS?

Refresh token należy przechowywać w Keychain z atrybutem kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly. Gwarantuje to szyfrowanie tokena, niedostępność przy zdjętym haśle i wyklucza synchronizację przez iCloud. Używanie UserDefaults lub CoreData do przechowywania tokena jest kategorycznie zabronione.

Podsumowanie

  • Refresh Token — długożyjący token do odświeżania access token bez re-login
  • Krótki TTL access token (15–60 min) minimalizuje szkody przy wycieku
  • Token rotation — każde odświeżenie zwraca nowy refresh token, stary jest unieważniany
  • Reuse detection — wykrywa kradzież tokena i blokuje sesję
  • Przechowywanie — iOS Keychain, Android EncryptedSharedPreferences (AES256-GCM)
  • Serwerowe odwołanie — usunięcie refresh token z bazy danych przy logout lub zmianie hasła
  • Refresh token nigdy nie jest przesyłany ze zwykłymi żądaniami API

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również