Keychain Basics
Keychain Basics
Store small secrets (tokens, passwords) securely using Keychain APIs with proper access control.
Store a Secret (Add)
Use SecItemAdd with a dictionary describing the item.
Syntax:
SecItemAdd(attrs as CFDictionary, nil)- class
kSecClassGenericPassword - account/service keys.
Example
import Security
func saveToken(_ token: String) {
let data = token.data(using: .utf8)!
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: "com.example.auth",
kSecAttrAccount as String: "session",
kSecValueData as String: data,
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock
]
SecItemDelete(query as CFDictionary) // replace if exists
let status = SecItemAdd(query as CFDictionary, nil)
assert(status == errSecSuccess)
}
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Keychain Add Example")
.padding()
}
}
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup { ContentView() }
}
}
This example writes a token as a generic password, replacing any existing value for the same service/account.
Read a Secret (Query)
Use SecItemCopyMatching with kSecReturnData to get the stored bytes.
Syntax: SecItemCopyMatching(query as CFDictionary, &item)
Example
import Security
func loadToken() -> String? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: "com.example.auth",
kSecAttrAccount as String: "session",
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
guard status == errSecSuccess, let data = item as? Data else { return nil }
return String(data: data, encoding: .utf8)
}
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Keychain Query Example")
.padding()
}
}
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup { ContentView() }
}
}
This example reads the previously saved token by matching on service/account and returning the data.
Update or Delete
Update with SecItemUpdate passing an attributes-to-update dictionary; delete with SecItemDelete.
Syntax:
SecItemUpdate(query, updates)SecItemDelete(query)
Example
import Security
func deleteToken() {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: "com.example.auth",
kSecAttrAccount as String: "session",
]
SecItemDelete(query as CFDictionary)
}
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Keychain Delete Example")
.padding()
}
}
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup { ContentView() }
}
}
This example removes the saved secret. Use update when you need to change value or attributes.
Tip: Prefer Keychain for credentials; avoid storing secrets in UserDefaults.