Overview
KeychainService provides persistent storage for R2 credentials. Despite its name, this implementation uses UserDefaults rather than the system Keychain, which is appropriate for a personal single-user tool where credentials are stored on the user’s own machine.
Located at:
Fiaxe/Services/KeychainService.swift:6Type Definition
Methods
saveAll()
Saves an array of R2 credentials to persistent storage.[R2Credentials]
required
Array of R2 credentials to save. Replaces any previously saved credentials.
Implementation Details
- Encodes the credentials array to JSON using
JSONEncoder - Stores the JSON data in
UserDefaultsunder the key"fiaxe.r2credentials" - Automatically synchronizes to disk via
UserDefaults
loadAll()
Retrieves all stored R2 credentials from persistent storage.Implementation Details
- Attempts to load data from
UserDefaults - If no data exists, returns an empty array
- First tries to decode as an array of credentials (current format)
- Falls back to decoding a single credential object (legacy format)
- Automatically wraps legacy single credential in an array
- Returns empty array if decoding fails
deleteAll()
Removes all stored credentials from persistent storage.Implementation Details
UserDefaults.
Storage Implementation
The service uses a simple key-value approach:UserDefaults.
Data Format
Credentials are stored as JSON-encodedR2Credentials objects:
Usage Examples
Migration Support
TheloadAll() method includes backward compatibility:
Security Considerations
When to Use UserDefaults vs Keychain
Use UserDefaults (current approach) when:- Building a personal single-user tool
- Credentials are for the user’s own accounts
- Simplicity is more important than maximum security
- Running on the user’s own trusted machine
- Building a production app for distribution
- Handling credentials for multiple users
- Need encrypted storage
- Require secure credential synchronization
- Need to prevent unauthorized access
Persistence Guarantees
UserDefaults automatically persists changes to disk, but synchronization is asynchronous. For critical operations, you can force synchronization:Testing
For testing, you can use a separateUserDefaults suite:
Related Services
- R2UploadService - Uses credentials for uploads
- R2BrowseService - Uses credentials for browsing
- AWSV4Signer - Uses credentials for request signing