markbattistella/keychainkit
`KeychainKit` is a Swift package that provides a clean, type-safe, and extensible API for securely storing, retrieving, and managing values in the system Keychain. It supports primitives, collections, `Codable` types, synchronisation options, accessibility controls, and automated
Features
- Type-safe Keychain Keys: Define strongly typed keys by conforming to
KeychainKeyRepresentable, with automatic prefixing. - Secure Storage for Multiple Types: Built-in support for:
- Bool, Int, Float, Double - String, Data, Date, URL - Arrays and dictionaries - Any Codable type
- Flexible Synchronisation: Control whether items sync via iCloud (
KeychainSync). - Accessibility Options: Adjust Keychain accessibility via
KeychainAccessible. - Utility Functions: Persistent references, accessibility lookup, existence checks, and full key listing.
- Migration Support: Built-in method to migrate Keychain contents between service names and access groups.
- Automatic Prefixing: Derived from your bundle identifier with optional custom prefixes.
Installation
Add KeychainKit to your Swift project using Swift Package Manager.
dependencies: [
.package(url: "https://github.com/markbattistella/KeychainKit", from: "1.0.0")
]Usage
Defining Keys
Define your Keychain keys using an enum conforming to KeychainKeyRepresentable:
enum KeychainKey: String, KeychainKeyRepresentable {
case authToken
case userProfile
case lastLogin
}Optionally override the prefix:
enum SecureKey: String, KeychainKeyRepresentable {
static let keyPrefix: String? = "com.example.custom"
case sessionID
}Storing Values
Store primitive types, strings, data, or any Encodable value:
let keychain = Keychain.standard
keychain.set("abc123", for: KeychainKey.authToken)
keychain.set(Date(), for: KeychainKey.lastLogin)
keychain.set(123, for: KeychainKey.userProfile)Or using the throwing version:
try keychain.setThrowing(User(id: 9, name: "Jane"), for: KeychainKey.userProfile)Retrieving Values
Retrieve values using convenient typed accessors:
let token = keychain.string(for: KeychainKey.authToken)
let loginDate = keychain.date(for: KeychainKey.lastLogin)
let user: User? = keychain.value(for: KeychainKey.userProfile)Working with URLs, Arrays, and Dictionaries
let website = keychain.url(for: KeychainKey.authToken)
let scores: [Int]? = keychain.array(for: KeychainKey.userProfile)
let metadata: [String: String]? = keychain.dictionary(for: KeychainKey.userProfile)Using iCloud Keychain Sync
keychain.set("abc123", for: KeychainKey.authToken, sync: .iCloud)
let token = keychain.string(for: KeychainKey.authToken, sync: .iCloud)Controlling Accessibility
try keychain.setThrowing(
"secret",
for: KeychainKey.authToken,
accessible: .whenPasscodeSetThisDeviceOnly
)
let level = keychain.accessibility(for: KeychainKey.authToken)Listing and Checking Keys
let allKeys = keychain.allKeys()
let exists = keychain.exists(for: KeychainKey.authToken)Removing Items
keychain.remove(for: KeychainKey.authToken)
keychain.removeLocalAndCloud(for: KeychainKey.authToken) // local + iCloud
keychain.removeAll() // all keys under current serviceNameMigration
KeychainKit supports migrating Keychain contents between service names or access groups:
let result = Keychain.migrate(
from: "old.group",
oldServiceName: "old.service",
to: "new.group",
newServiceName: "new.service",
mode: .perform
)
print(result.migrated)
print(result.failed)Use .dryRun to simulate migration without making changes:
let result = Keychain.migrate(
from: "old.group",
oldServiceName: "old.service",
to: "new.group",
mode: .dryRun
)License
KeychainKit is available under the MIT license. See the LICENCE file for more information.
Package Metadata
Repository: markbattistella/keychainkit
Default branch: main
README: README.md