Skip to content
AIQGM

Where a session token should live on iOS

UserDefaults is convenient, and it's a plain property list. Tokens belong in the Keychain, with an accessibility class chosen on purpose.

Auth tokens in UserDefaults are one of the most common findings in iOS app reviews. It's a property list inside the app container: it ends up in unencrypted device backups and is readable on a jailbroken phone.

The Keychain is encrypted by the system, and the accessibility attribute decides when the item can be read and whether it may leave the device:

Swiftswift
func saveToken(_ token: String, for account: String) throws {
    let base: [String: Any] = [
        kSecClass as String:       kSecClassGenericPassword,
        kSecAttrService as String: "com.example.app.session",
        kSecAttrAccount as String: account,
    ]
    SecItemDelete(base as CFDictionary)          // replace any previous value

    var item = base
    item[kSecValueData as String] = Data(token.utf8)
    // Readable after the first unlock (so background refresh works),
    // never restored onto a different device from a backup.
    item[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly

    let status = SecItemAdd(item as CFDictionary, nil)
    guard status == errSecSuccess else { throw KeychainError.unhandled(status) }
}

ThisDeviceOnly means a user restoring a backup to a new phone signs in again. That's usually what you want for a session token, and usually not what you want for a user's saved preferences. It's a product decision, so we raise it rather than pick silently.

This comes from our mobile apps work.

Tell us what you're working on.

A few paragraphs is plenty. We'll read it, reply by email, and if it looks like a fit, set up a 30-minute Google Meet with an engineer.