Authentication & 2FA
Relevant source files
The following files were used as context for generating this wiki page:
- Putio/Features/Auth/LoginViewController.swift
- Putio/Features/Auth/TwoFactorAuth/TwoFactorRecoveryCodesViewController.swift
- Putio/Features/Auth/TwoFactorAuth/TwoFactorRecoveryCodesViewModel.swift
- Putio/AppDelegate.swift
- Putio/Features/Auth/AuthErrors.swift
- Putio/Common/API/PutioSDK.swift
- PutioTests/PutioKeychainTests.swift
- Putio/Features/Settings/Authorizations/AuthAppsTableViewController.swift
The Authentication and Two-Factor Authentication (2FA) system in the put.io iOS application manages secure user access through OAuth2 browser-based flows, keychain-backed session persistence, and multi-factor security layers. The system ensures that access tokens are handled securely and provides users with tools to manage active sessions and recovery options.
The architecture relies on ASWebAuthenticationSession for initial login, PutioKeychain for sensitive data storage, and the PutioSDK for communicating with the put.io backend services. It also includes comprehensive support for 2FA, including TOTP generation and recovery code management.
OAuth2 Authentication Flow
The primary authentication mechanism uses an OAuth2 flow initiated within a secure web session. Users are redirected to the put.io login page, and upon successful authentication, the app captures an access token via a custom URL scheme (putio://auth).
Web Authentication Process
The LoginViewController utilizes ASWebAuthenticationSession to provide a secure modal interface for user credentials. It generates a unique state parameter for each session to prevent cross-site request forgery (CSRF) during the callback.
Token Validation and Matching
The application strictly validates the callback URL. It ensures the scheme is putio, the host is auth, and the returned state matches the currentOAuthState stored at the start of the session. If any check fails, the authentication is aborted with a localized error.
Sources: Putio/Features/Auth/LoginViewController.swift:82-108
Session Management and Persistence
Once a token is acquired, it is persisted and used to bootstrap the user's environment, including fetching account information and configurations.
Keychain Persistence
Access tokens are stored in the iOS Keychain using a scoped service key. This ensures that the session survives app restarts and is protected by the operating system's hardware-backed security.
Sources: PutioTests/PutioKeychainTests.swift:10-18
App Bootstrapping
During didFinishLaunchingWithOptions, the AppDelegate checks for an existing token. If found, it automatically sets the API token and attempts to fetch user data.
| Component | Responsibility |
|---|---|
PutioKeychain | Stores and retrieves the OAuth access token from secure storage. |
AppDelegate.authenticate(token:) | Configures the SDK and triggers account synchronization. |
AppDelegate.fetchUser() | Concurrent fetch of account info and configuration via DispatchGroup. |
PutioRealm.replaceUserSession(...) | Updates the local database with the latest user/config data. |
Sources: Putio/AppDelegate.swift:145-152, Putio/AppDelegate.swift:154-192, Putio/AppDelegate.swift:203-219
Two-Factor Authentication (2FA)
The application supports enhanced security through 2FA, allowing users to manage recovery codes and monitor authorized applications.
Recovery Code Management
Users can view and regenerate recovery codes. These codes are critical for regaining access if the primary 2FA method is lost. The system tracks which codes have been used.
- View Codes: Fetches current codes from
api.getRecoveryCodes. - Regenerate Codes: Invalidation of old codes and creation of new ones via
api.regenerateRecoveryCodes. - Copy to Clipboard: Allows users to "Copy all" unused codes for safe keeping.
Authorized Applications
The AuthAppsTableViewController allows users to audit and revoke active OAuth grants. This provides a "Where you are logged in" feature, allowing users to terminate sessions on other devices.
Sources: Putio/Features/Settings/Authorizations/AuthAppsTableViewController.swift:11-54
Error Handling
Authentication-specific errors are localized using a dedicated AuthErrors structure. This maps SDK-level error types (like invalid_code or HTTP 401) to user-friendly messages and recovery suggestions.
| Error Scenario | Matcher | User Message |
|---|---|---|
| Login Failure | HTTP 401 | "Invalid username or password" |
| Invalid 2FA Code | invalid_code / INVALID_VALUE | "The code you entered is invalid" |
| 2FA Code Not Found | code_not_found | "The code you entered is invalid" |
Sources: Putio/Features/Auth/AuthErrors.swift:6-45
Logout and Data Cleanup
When a user logs out, the system performs a comprehensive cleanup to ensure no sensitive data remains:
- Clears the token from
PutioKeychain. - Clears the token from the active
PutioSDKinstance. - Clears video playback positions.
- Logs out from Intercom.
- Redirects the user back to the login screen.
Sources: Putio/AppDelegate.swift:250-256
The Authentication and 2FA system provides a secure foundation for the put.io iOS app, combining standard OAuth2 flows with robust multi-factor security and centralized session management. By leveraging the iOS Keychain and strict state validation, the system protects user credentials while maintaining a seamless transition between authorized and unauthorized states.