Реалізація авторизації через OAuth 2.0 в мобільному приложенні
OAuth 2.0 в мобільному контексті — це не те саме, що OAuth 2.0 в вебе. Authorization Code Flow з PKCE (Proof Key for Code Exchange) — єдиний правильний варіант для native приложень. Implicit Flow офіційно deprecated в RFC 9700. Client Credentials не підходить — немає користувацького контексту. Якщо хто-небудь пропонує Implicit Flow для мобілки у 2024 — це червоний прапорець.
Чому PKCE обов'язковий
Native приложення не може безпечно зберігати client_secret. Файл APK/IPA декомпілюється за хвилини — будь-який секрет, зашитий в бінарник, вважається скомпрометованим за визначенням. PKCE вирішує цю проблему без client_secret: генеруємо code_verifier (випадкова рядок 43–128 символів), хешуємо SHA-256 → code_challenge, передаємо challenge при запиті авторизації. При обміні коду на токен передаємо оригінальний verifier — сервер перевіряє збіг. Перехопити code та використовувати без verifier неможливо.
code_verifier генеруємо криптографічно:
// iOS
var buffer = [UInt8](repeating: 0, count: 32)
_ = SecRandomCopyBytes(kSecRandomDefault, buffer.count, &buffer)
let verifier = Data(buffer).base64URLEncodedString()
// Android
val bytes = ByteArray(32)
SecureRandom().nextBytes(bytes)
val verifier = Base64.encodeToString(bytes, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP)
Redirect URI та Custom URL Schemes
Другий болючий момент — перехват redirect. Custom URL Scheme (myapp://callback) може бути перехоплений іншим приложенням на пристрої, зареєстрованим з тим же scheme. Правильний варіант — HTTPS App Links (Android) та Universal Links (iOS). Сервер авторизації редиректить на https://yourapp.com/callback, система перевіряє assetlinks.json/apple-app-site-association та передає URL безпосередньо вашому приложенню.
Налаштування Universal Links вимагає:
- AASA-файл на домені за адресою
https://yourapp.com/.well-known/apple-app-site-association -
Associated Domainscapability в Xcode з записомapplinks:yourapp.com - Обробка URL в
scene(_:continue:)абоapplication(_:continue:restorationHandler:)
На Android — файл Digital Asset Links та intent-filter з autoVerify="true".
Бібліотеки
Не пишемо OAuth 2.0 + PKCE з нуля. Використовуємо:
- iOS: AppAuth-iOS (openid.net, поточна версія 1.7+)
- Android: AppAuth-Android
- React Native: react-native-app-auth
- Flutter: flutter_appauth
AppAuth береж на себе генерацію PKCE, відкриття браузера (через ASWebAuthenticationSession на iOS, Custom Tabs на Android), обробку redirect та обмін коду на токен.
Зберігання токенів
Access token — в пам'яті (@State, ViewModel). Не в UserDefaults, не в SharedPreferences. Refresh token — у Keychain (iOS) або EncryptedSharedPreferences/Android Keystore (Android). Access token живе 15–60 хвилин, refresh — дні або тижні. Різна чутливість — різний рівень зберігання.
Перехват refresh token з SharedPreferences на рутованому Android-пристрої — реальний вектор атаки. EncryptedSharedPreferences з androidx.security:security-crypto закриває цей сценарій на пристроях з Android Keystore (API 23+).
Робота з кількома identity providers
Типовий кейс: вхід через Google, Apple, корпоративний SAML IdP. Архітектурно — єдиний OAuthService з протоколом/інтерфейсом, різні провайдери як конкретні реалізації. Не змішуємо токени різних провайдерів — кожен зберігається під своїм ключем у Keychain/Keystore.
"Sign in with Apple" обов'язковий для App Store, якщо є вхід через Google або Facebook — гайдлайн 4.8. Порушення → відхилення на ревю.
Процес та терміни
Аудит існуючої auth (якщо є) → вибір/налаштування Authorization Server → реалізація PKCE flow через AppAuth → налаштування Universal/App Links → зберігання токенів → refresh flow → тестування на реальних пристроях → інтеграційні тесты з Authorization Server.
Терміни: 5–10 робочих днів для одного провайдера. Кожен додатковий провайдер — плюс 2–3 дні. Налаштування корпоративного Authorization Server на стороні сервера не входить у цю оцінку.







