Keychain Access Control
Gate items behind biometrics and device unlock.
Keychain Access Control is a free Swift Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Controlling When Secrets Are Readable
Storing a secret is only half the job — you must control when it can be read. The Keychain offers accessibility classes and access-control flags that gate items behind device unlock, passcode, or biometrics. This protects data if a device is lost.
import Security
// Two layers of control:
// kSecAttrAccessible -> when readable (lock state)
// SecAccessControl -> user presence / biometricsThe kSecAttrAccessible Key
kSecAttrAccessible sets the accessibility class on add. It decides whether an item is available always, only after first unlock, or only while the device is unlocked. Pick the strictest level your feature allows.
import Security
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "user",
kSecValueData as String: Data("secret".utf8),
kSecAttrAccessible as String:
kSecAttrAccessibleWhenUnlocked
]
_ = queryWhenUnlocked
kSecAttrAccessibleWhenUnlocked makes the item readable only while the device is unlocked. Background tasks running while locked cannot reach it. This is the sensible default for most session tokens.
import Security
// Readable only while unlocked; blocked when locked.
let level = kSecAttrAccessibleWhenUnlocked
_ = levelAfterFirstUnlock
kSecAttrAccessibleAfterFirstUnlock keeps the item readable from the first unlock after boot until the next reboot — even while later locked. Use it for secrets a background process needs, like a push-handling token.
import Security
// Available after the first unlock post-boot,
// including while subsequently locked.
let level = kSecAttrAccessibleAfterFirstUnlock
_ = levelThisDeviceOnly Variants
Each accessibility class has a ...ThisDeviceOnly form. These items are excluded from encrypted backups and never migrate to a new device. Use them for keys that should never leave this hardware.
import Security
// Never backed up, never migrated:
let local = kSecAttrAccessibleWhenUnlockedThisDeviceOnly
_ = localWhen Passcode Is Set
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly stores the item only if the user has a passcode, and deletes it if they remove the passcode. It guarantees the secret is always passcode-protected.
import Security
let level =
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
// Item vanishes if the user disables their passcode.
_ = levelSecAccessControl for User Presence
Beyond lock state, SecAccessControlCreateWithFlags builds a policy requiring active user authentication — biometrics or passcode — at read time. You attach it via kSecAttrAccessControl instead of (or with) the accessible key.
import Security
func makeControl() -> SecAccessControl? {
return SecAccessControlCreateWithFlags(
nil,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
.userPresence,
nil)
}Access Control Flags
Flags refine the requirement: .userPresence allows biometric or passcode fallback; .biometryCurrentSet invalidates the item if enrolled fingerprints/faces change; .devicePasscode forces passcode entry. Combine them to express your security needs.
import Security
// .userPresence -> biometric OR passcode
// .biometryAny -> any enrolled biometric
// .biometryCurrentSet -> invalidate on biometric change
// .devicePasscode -> passcode only
let flags: SecAccessControlCreateFlags = [.userPresence]
_ = flagsAdding a Protected Item
To store a biometric-gated secret, put the SecAccessControl object under kSecAttrAccessControl. Any later read prompts the user to authenticate before the data is returned.
import Security
func saveProtected(_ data: Data, account: String,
control: SecAccessControl) -> Bool {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: account,
kSecValueData as String: data,
kSecAttrAccessControl as String: control]
return SecItemAdd(query as CFDictionary, nil)
== errSecSuccess
}Reading Prompts the User
Reading a protected item triggers the authentication UI automatically. You can supply a reason string via kSecUseOperationPrompt so the prompt explains why access is needed. The read blocks until the user authenticates or cancels.
import Security
func readProtected(account: String) -> Data? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: account,
kSecReturnData as String: true,
kSecUseOperationPrompt as String:
String(localized: "Unlock your saved key")]
var out: CFTypeRef?
return SecItemCopyMatching(query as CFDictionary,
&out) == errSecSuccess ? out as? Data : nil
}Choosing the Right Level
Match the policy to the risk:
- Session token used in background:
AfterFirstUnlock. - UI-only token:
WhenUnlocked. - High-value secret:
SecAccessControlwith.userPresenceand aThisDeviceOnlyclass.
Stricter is safer, but breaks background access — balance both.
import Security
// High-value: biometric-gated, device-bound, no backup
let control = SecAccessControlCreateWithFlags(
nil,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
.userPresence, nil)
_ = controlQuick Check
Recall which accessibility class suits a background-needed secret.
Recap
You learned to gate Keychain items:
kSecAttrAccessiblesets lock-state availability:WhenUnlocked,AfterFirstUnlock, and...ThisDeviceOnlyvariants that skip backups.WhenPasscodeSetThisDeviceOnlyties the item to having a passcode.SecAccessControlwith flags like.userPresenceor.biometryCurrentSetrequires authentication at read time.- Choose the strictest level that still allows your access pattern.
Frequently asked questions
Is the “Keychain Access Control” lesson free?
Yes — the full text of “Keychain Access Control” is free to read here on the web, and the Swift Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.
What will I learn in “Keychain Access Control”?
Gate items behind biometrics and device unlock. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Swift Academy?
No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Keychain Access Control” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Swift Academy lesson?
Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Storing Secrets in the Keychain
- Keychain Access Control
- Biometric Authentication
- Data Protection and Encryption