SecureStorage is a Swift package that provides a simple, secure, and type-safe way to store, retrieve, and delete Codable values using Apple's Keychain. It is designed with SwiftUI in mind, offering a property wrapper (@SecStorage) for easy integration into your views, as well as a protocol-based approach (Securable) for managing secure persistence across your app.
-
Property Wrapper (
SecStorage)
Easily wrap any Codable value for secure storage with minimal boilerplate code. Automatically encodes to and decodes from JSON when saving or retrieving data. -
Securable Protocol
Conform your types to theSecurableprotocol to gain default implementations for secure storage, retrieval, and clearing of persisted data. -
Keychain Integration
Leverages the Security framework to handle secure storage with methods for adding, retrieving, and deleting Keychain items. -
Error Handling
Provides a customSecureStorageErrorenum to handle various error cases, such as encoding/decoding issues and Keychain operation failures.
Add SecureStorage to your project by updating your Package.swift file:
dependencies: [
.package(url: "https://github.com/oldgrowth-games/SecureStorage.git", from: "1.0.0")
]Then, add "SecureStorage" as a dependency to your target:
.target(
name: "YourTargetName",
dependencies: ["SecureStorage"]
)Alternatively, in Xcode, navigate to File > Add Package Dependencies... and enter the repository URL.
Integrate secure storage directly into your SwiftUI views by annotating your properties with @SecStorage.
import SwiftUI
import SecureStorage
struct UserProfile: Codable {
var username: String
var email: String
}
struct ContentView: View {
// "userProfile" is the key for secure storage.
@SecStorage("userProfile") var userProfile: UserProfile?
var body: some View {
VStack {
if let profile = userProfile {
Text("Username: \(profile.username)")
Text("Email: \(profile.email)")
} else {
Text("No user profile found.")
}
}
.onAppear {
// Example: Save a user profile if none exists.
if userProfile == nil {
userProfile = UserProfile(username: "JohnDoe", email: "john.doe@example.com")
}
}
}
}For more complex data types or when you need custom storage logic, conform your Codable type to Securable.
import SecureStorage
struct User: Codable, Securable {
// Unique key for secure storage.
var securableKey: String { "currentUser" }
var name: String
var age: Int
}
// Storing the user:
let user = User(name: "Jane Doe", age: 28)
user.store()
// Retrieving the user:
do {
let storedUser = try User(securableKey: "currentUser")
print("Retrieved User: \(storedUser.name)")
} catch {
print("Error retrieving user: \(error)")
}
// Clearing the stored data:
user.clear()A property wrapper that provides a convenient interface for storing and retrieving Codable values using a unique key.
- wrappedValue: Automatically encodes/decodes the value to/from JSON stored in the Keychain.
Defines a contract for securely persisting data. Types conforming to Securable are required to provide a unique key and gain default implementations for:
- Initialization: Retrieve and decode stored data.
- Store: Encode and save the instance securely.
- Clear: Delete the stored data from the Keychain.
A utility struct that wraps the Keychain operations:
- store(key:value:): Stores a Codable value by encoding it as JSON.
- store(key:data:): Stores raw Data.
- retrieve(key:): Retrieves stored data.
- delete(key:): Deletes data associated with the given key.
An error enumeration that encapsulates various errors which may occur during secure storage operations:
- codable(Error): Errors during encoding/decoding.
- itemDelete(OSStatus): Errors when deleting a Keychain item.
- itemAdd(OSStatus): Errors when adding a new Keychain item.
- itemCopyMatching(OSStatus): Errors during data retrieval.
Contributions are welcome! If you find a bug, have an idea for a new feature, or want to improve the documentation, please open an issue or submit a pull request.
- Fork the repository.
- Create a feature branch (
git checkout -b feature/YourFeature). - Commit your changes.
- Push to the branch (
git push origin feature/YourFeature). - Open a pull request.
This project is available under the MIT License.
For any questions, suggestions, or feedback, please open an issue