Bird
Raised Fist0
iOS Swiftmobile~5 mins

Keychain for secure storage in iOS Swift

Choose your learning style10 modes available
Introduction

Keychain helps you keep sensitive data safe on your iPhone. It stores passwords and keys securely so only your app can access them.

Saving a user password after login to avoid asking every time.
Storing an authentication token securely for API calls.
Keeping a secret key for encrypting user data.
Saving sensitive user preferences that should not be visible.
Remembering login credentials safely between app launches.
Syntax
iOS Swift
import Security

// To save data
let query: [String: Any] = [
  kSecClass as String: kSecClassGenericPassword,
  kSecAttrAccount as String: "userEmail",
  kSecValueData as String: "user@example.com".data(using: .utf8)!
]
SecItemAdd(query as CFDictionary, nil)

// To read data
let query: [String: Any] = [
  kSecClass as String: kSecClassGenericPassword,
  kSecAttrAccount as String: "userEmail",
  kSecReturnData as String: kCFBooleanTrue!
]
var item: CFTypeRef?
SecItemCopyMatching(query as CFDictionary, &item)

Use kSecClassGenericPassword for most secure storage needs.

Always convert strings to Data before saving.

Examples
This saves an API token securely in the keychain.
iOS Swift
let addQuery: [String: Any] = [
  kSecClass as String: kSecClassGenericPassword,
  kSecAttrAccount as String: "apiToken",
  kSecValueData as String: "12345abcde".data(using: .utf8)!
]
SecItemAdd(addQuery as CFDictionary, nil)
This reads the saved API token from the keychain and prints it.
iOS Swift
let getQuery: [String: Any] = [
  kSecClass as String: kSecClassGenericPassword,
  kSecAttrAccount as String: "apiToken",
  kSecReturnData as String: kCFBooleanTrue!
]
var result: CFTypeRef?
let status = SecItemCopyMatching(getQuery as CFDictionary, &result)
if status == errSecSuccess, let data = result as? Data, let token = String(data: data, encoding: .utf8) {
  print("Token: \(token)")
}
Sample App

This app saves a password securely in the keychain and then reads it back. It prints messages to the console to show success or failure.

iOS Swift
import UIKit
import Security

class ViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()

    let account = "userEmail"
    let password = "secret123"

    // Save password
    let addQuery: [String: Any] = [
      kSecClass as String: kSecClassGenericPassword,
      kSecAttrAccount as String: account,
      kSecValueData as String: password.data(using: .utf8)!
    ]
    SecItemDelete(addQuery as CFDictionary) // Remove old item if exists
    let status = SecItemAdd(addQuery as CFDictionary, nil)

    if status == errSecSuccess {
      print("Password saved successfully.")
    } else {
      print("Failed to save password.")
    }

    // Retrieve password
    let getQuery: [String: Any] = [
      kSecClass as String: kSecClassGenericPassword,
      kSecAttrAccount as String: account,
      kSecReturnData as String: kCFBooleanTrue!
    ]
    var result: CFTypeRef?
    let copyStatus = SecItemCopyMatching(getQuery as CFDictionary, &result)

    if copyStatus == errSecSuccess, let data = result as? Data, let savedPassword = String(data: data, encoding: .utf8) {
      print("Retrieved password: \(savedPassword)")
    } else {
      print("Failed to retrieve password.")
    }
  }
}
OutputSuccess
Important Notes

Always delete old keychain items before adding new ones with the same key to avoid duplicates.

Keychain data persists even if the app is deleted and reinstalled unless you change the keychain access group.

Test keychain code on a real device because the simulator may behave differently.

Summary

Keychain stores sensitive data securely on iOS devices.

Use SecItemAdd to save and SecItemCopyMatching to read data.

Always convert strings to Data before saving and back to strings after reading.

Practice

(1/5)
1. What is the primary purpose of using the iOS Keychain in app development?
easy
A. To store large media files for offline use
B. To securely store sensitive data like passwords and tokens
C. To cache images for faster loading
D. To manage app user interface layouts

Solution

  1. Step 1: Understand Keychain's role

    The Keychain is designed to securely store sensitive information such as passwords, tokens, and certificates.
  2. Step 2: Differentiate from other storage

    It is not meant for large files, caching images, or UI management, which are handled by other systems.
  3. Final Answer:

    To securely store sensitive data like passwords and tokens -> Option B
  4. Quick Check:

    Keychain = Secure sensitive data [OK]
Hint: Keychain is for secrets, not files or UI [OK]
Common Mistakes:
  • Thinking Keychain stores large files
  • Confusing Keychain with cache or UI storage
  • Using Keychain for non-sensitive data
2. Which Swift code snippet correctly converts a String to Data for saving in Keychain?
easy
A. let data = myString.toData()
B. let data = Data(myString)
C. let data = myString.data(using: .utf8)
D. let data = Data.fromString(myString)

Solution

  1. Step 1: Identify correct String to Data conversion

    In Swift, String has a method data(using:) that converts it to Data using a specified encoding like UTF-8.
  2. Step 2: Check method validity

    Options B, C, and D use invalid or non-existent methods for this conversion.
  3. Final Answer:

    let data = myString.data(using: .utf8) -> Option C
  4. Quick Check:

    String.data(using:) = correct conversion [OK]
Hint: Use .data(using: .utf8) to convert String to Data [OK]
Common Mistakes:
  • Using non-existent methods like toData()
  • Trying to initialize Data directly with String
  • Forgetting to specify encoding
3. Given the following Swift code snippet, what will be the output if the keychain item exists and contains the string "secret123"?
let query: [String: Any] = [
  kSecClass as String: kSecClassGenericPassword,
  kSecAttrAccount as String: "userKey",
  kSecReturnData as String: true
]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
if status == errSecSuccess, let data = item as? Data, let password = String(data: data, encoding: .utf8) {
  print(password)
} else {
  print("No data found")
}
medium
A. Error: Keychain item missing
B. No data found
C. nil
D. secret123

Solution

  1. Step 1: Understand SecItemCopyMatching behavior

    If the keychain item with key "userKey" exists, SecItemCopyMatching returns errSecSuccess and the data is assigned to item.
  2. Step 2: Convert data to String

    The code safely unwraps the data and converts it to a UTF-8 string, then prints it.
  3. Final Answer:

    secret123 -> Option D
  4. Quick Check:

    Keychain item found = print stored string [OK]
Hint: If status is success, data prints as stored string [OK]
Common Mistakes:
  • Assuming print shows 'No data found' when item exists
  • Not casting item to Data before conversion
  • Ignoring status check before unwrapping
4. Identify the error in this Swift code snippet that tries to save a password to Keychain:
let password = "mypassword"
let data = password.data(using: .utf8)
let query: [String: Any] = [
  kSecClass as String: kSecClassGenericPassword,
  kSecAttrAccount as String: "userKey",
  kSecValueData as String: data
]
let status = SecItemAdd(query as CFDictionary, nil)
if status == errSecSuccess {
  print("Saved")
} else {
  print("Failed")
}
medium
A. data is optional and should be unwrapped before use
B. kSecAttrAccount key is incorrect
C. SecItemAdd requires a non-nil second parameter
D. kSecClassGenericPassword is not a valid class

Solution

  1. Step 1: Check data conversion

    The data(using:) method returns an optional Data?. It must be safely unwrapped before use.
  2. Step 2: Identify usage error

    Passing optional data directly to kSecValueData can cause runtime issues or failure to save.
  3. Final Answer:

    data is optional and should be unwrapped before use -> Option A
  4. Quick Check:

    Optional Data must be unwrapped before Keychain save [OK]
Hint: Always unwrap optional Data before saving to Keychain [OK]
Common Mistakes:
  • Passing optional Data without unwrapping
  • Misusing Keychain attribute keys
  • Assuming SecItemAdd second parameter cannot be nil
5. You want to update an existing password stored in Keychain for the account "userKey". Which approach correctly updates the password securely?
hard
A. Use SecItemUpdate with a query matching the account and provide new kSecValueData
B. Call SecItemAdd again with the same account and new password
C. Delete the old item with SecItemDelete then add a new item with SecItemAdd
D. Modify the stored password directly by changing the Keychain file

Solution

  1. Step 1: Understand Keychain update method

    The correct way to update an existing Keychain item is to use SecItemUpdate with a query to find the item and attributes to change.
  2. Step 2: Evaluate alternatives

    Using SecItemAdd with the same key will fail because the item exists. Deleting then adding works but is less efficient. Direct file modification is unsafe and unsupported.
  3. Final Answer:

    Use SecItemUpdate with a query matching the account and provide new kSecValueData -> Option A
  4. Quick Check:

    Update Keychain = SecItemUpdate [OK]
Hint: Use SecItemUpdate to change existing Keychain data [OK]
Common Mistakes:
  • Trying to add duplicate items with SecItemAdd
  • Deleting then adding instead of updating
  • Attempting unsafe direct file edits
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard