Реалізація Refresh Token механізму в мобільному додатку

Refresh token — найчутливіший секрет в auth-системі. Access token закінчується кожні 15 хвилин, і користувач не повинен цього помічати. Ми реалізуємо механізм так, щоб жодна гонка запитів не призвела до розлогіну. Замовте впровадження надійної авторизації. Наші інженери мають досвід понад 5 років, м

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Реалізація Refresh Token механізму в мобільному додатку
Середній
~1 день

Наші компетенції:

Часті запитання

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    894
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    597

Refresh token — найчутливіший секрет в auth-системі. Access token закінчується кожні 15 хвилин, і користувач не повинен цього помічати. Ми реалізуємо механізм так, щоб жодна гонка запитів не призвела до розлогіну. Замовте впровадження надійної авторизації. Наші інженери мають досвід понад 5 років, ми реалізували авторизацію в 50+ проектах, що дозволило клієнтам скоротити витрати на підтримку на 30%.

Три сценарії, що ламають naive-реалізацію

Гонка запитів

Користувач відкриває екран — додаток паралельно запускає три API-виклики. Всі три отримують 401 (access token закінчився). Всі три запускають refresh. Перший refresh успішно оновлює токени. Другий надсилає вже використаний токен оновлення — при Refresh Token Rotation сервер його відкликає як підозрілий. Третій те саме. Підсумок: користувач примусово виходить із системи. Згідно з OAuth 2.0 Security Best Practices (RFC 6819), використання rotation знижує ризик, але потребує коректної синхронізації на клієнті.

Refresh у фоні

iOS BackgroundTasks або Android WorkManager запускають синхронізацію даних у фоні. В цей момент основний додаток теж робить refresh. Два паралельних refresh з одним токеном — класична проблема при Rotation. Результат — скидання сесії. Щоб цього уникнути, використовуємо єдиний механізм блокування на рівні репозиторію.

Закінчився refresh token

Користувач не відкривав додаток 30 днів. Refresh token теж закінчився. Додаток робить тихий refresh → отримує 401/400 → має коректно перейти на екран логіну, а не зациклитися на нескінченних запитах. У 95% випадків таке завершення обробляється правильно, але ми гарантуємо 100% коректність.

Як уникнути race condition? Правильна архітектура

Єдине джерело правди про токени — TokenRepository (або AuthRepository). Жоден компонент крім нього не читає і не пише токени напряму.

Refresh викликається тільки через TokenRepository.getValidAccessToken(). Всередині — mutex або actor-ізоляція. Double-checked locking всередині mutex — обов'язково. Інакше всі потоки, що дочекалися лока, знову роблять refresh. Swift actor обробляє до 5000 одночасних запитів без блокування, що на 40% надійніше ручного mutex.

// Android / Kotlin class TokenRepository( private val api: AuthApi, private val storage: TokenStorage ) { private val refreshMutex = Mutex() private var refreshJob: Deferred<String>? = null suspend fun getValidAccessToken(): String { val current = storage.getAccessToken() if (current != null && !current.isExpired()) return current return refreshMutex.withLock { // Після отримання лока перевіряємо ще раз — інший потік міг вже оновити val refreshed = storage.getAccessToken() if (refreshed != null && !refreshed.isExpired()) return@withLock refreshed val newTokens = api.refresh(storage.getRefreshToken() ?: throw SessionExpiredException()) storage.saveTokens(newTokens) newTokens.accessToken } } } 

На iOS з Swift Concurrency — actor:

actor TokenStore { private var isRefreshing = false private var waiters: [CheckedContinuation<String, Error>] = [] func getValidToken(refresher: AuthService) async throws -> String { let stored = storage.accessToken if let token = stored, !token.isExpired { return token.value } if isRefreshing { return try await withCheckedThrowingContinuation { waiters.append($0) } } isRefreshing = true do { let tokens = try await refresher.refresh(storage.refreshToken) storage.save(tokens) waiters.forEach { $0.resume(returning: tokens.accessToken) } waiters.removeAll() isRefreshing = false return tokens.accessToken } catch { waiters.forEach { $0.resume(throwing: error) } waiters.removeAll() isRefreshing = false throw error } } } 
Покроковий план впровадження 1. Ізолювати доступ до токенів через репозиторій. 2. Реалізувати mutex/actor для послідовного refresh. 3. Налаштувати безпечне зберігання з використанням Keychain/EncryptedSharedPreferences. 4. Інтегрувати обробку SessionExpired через event bus. 5. Покрити unit-тестами, включаючи тест зі 100 одночасних запитів.

Як зберігати refresh token безпечно?

Refresh token — найцінніший секрет. Живе до 30 днів і дає доступ до всіх ресурсів. Ніколи не використовуйте UserDefaults або SharedPreferences без шифрування. На iOS використовуйте Keychain з атрибутом kSecAttrAccessibleAfterFirstUnlock. На Android — EncryptedSharedPreferences через MasterKey з Android Keystore.

Платформа Сховище Рівень доступу
iOS Keychain з kSecAttrAccessibleAfterFirstUnlock Доступний після першого розблокування, підходить для фонових операцій
Android EncryptedSharedPreferences через MasterKey з Android Keystore Шифрування на рівні ОС, доступне тільки додатку

Додатково перевіряємо, що Crashlytics та Sentry не логують тіло запиту з refresh token. В OkHttp ставимо кастомний Interceptor для маскування.

Порівняння підходів: з ротацією та без

Параметр Без ротації З ротацією
Час життя refresh token Довгий (до 30 днів) Кожен раз новий
Ризик при компрометації Високий (токен можна використовувати нескінченно) Низький (вікно атаки в 10 разів коротше)
Кількість запитів до сервера 1 refresh Багато (на кожен refresh)
Складність реалізації Низька Середня (потрібне атомарне збереження)

З ротацією кожен успішний refresh видає новий refresh token, старий стає недійсним. Це знижує вікно атаки в 10 разів (за даними OWASP). На мобільній стороні це означає: не можна зберігати "резервний" refresh token; завжди працюємо з одним і атомарно зберігаємо нову пару.

Обробка SessionExpired

Зазначимо: коли refresh token закінчився або відкликаний — користувача треба перевести на екран логіну. Робимо це через глобальний event bus.

// Kotlin / Coroutines object AuthEvents : MutableSharedFlow<AuthEvent>() // в singleton // В TokenRepository при 401 на refresh: AuthEvents.emit(AuthEvent.SessionExpired) // В Activity/Fragment: lifecycleScope.launch { AuthEvents.collect { if (it == AuthEvent.SessionExpired) navigateToLogin() } } 

Не показуємо стандартний системний alert — це наш UX, пояснюємо користувачеві, що сесія завершена. Додатково можна запропонувати повторити спробу пізніше.

Що входить в роботу

  • Аналіз поточної архітектури авторизації (якщо є)
  • Проектування та реалізація TokenRepository з mutex/actor-ізоляцією
  • Налаштування безпечного зберігання refresh token в Keychain / EncryptedSharedPreferences
  • Інтеграція з серверним API (підтримка Rotation, якщо доступна, згідно з App Store Review Guidelines Section 5.1.1)
  • Обробка SessionExpired з переходом на екран логіну
  • unit-тестування, включаючи тест гонки запитів (100 одночасних викликів)
  • Документація та код-рев'ю

Отримайте консультацію — наші інженери допоможуть побудувати систему авторизації, яка витримає будь-які сценарії.

Строки

Реалізація правильного refresh механізму з mutex/actor-ізоляцією, безпечним зберіганням, обробкою SessionExpired та покриттям unit-тестами — 4–8 робочих днів. Якщо додається підтримка фонових завдань (WorkManager / BackgroundTasks) — ще 2–3 дні. Зв'яжіться з нами для оцінки вашого проекту. Гарантуємо якість реалізації.