This guide will walk you through using SAMKeychain to perform common keychain operations. We’ll cover storing, retrieving, and deleting passwords using both the simple class methods and the more advanced query interface.
Prerequisites
Before you begin, make sure you have:
Installed SAMKeychain (see Installation )
Imported SAMKeychain in your source file
Added the Security framework to your project
Your First Keychain Operation
Let’s start with the most common use case: storing and retrieving a password.
Import SAMKeychain
Add the import statement to your source file: #import <SAMKeychain/SAMKeychain.h>
Store a password
Save a password to the keychain using a service name and account: NSString * password = @"mySecretPassword123" ;
NSString * serviceName = @"com.yourcompany.yourapp" ;
NSString * account = @"user@example.com" ;
BOOL success = [SAMKeychain setPassword: password
forService: serviceName
account: account];
if (success) {
NSLog ( @"Password saved successfully!" );
} else {
NSLog ( @"Failed to save password" );
}
Use your app’s bundle identifier as the service name to avoid conflicts with other apps.
Retrieve the password
Get the password back from the keychain: NSString * retrievedPassword = [SAMKeychain passwordForService: serviceName
account: account];
if (retrievedPassword) {
NSLog ( @"Retrieved password: %@ " , retrievedPassword);
} else {
NSLog ( @"Password not found" );
}
Delete the password
Remove the password from the keychain when no longer needed: BOOL deleted = [SAMKeychain deletePasswordForService: serviceName
account: account];
if (deleted) {
NSLog ( @"Password deleted successfully!" );
} else {
NSLog ( @"Failed to delete password" );
}
Error Handling
For production code, you should always handle errors properly. Here’s how to use the error-aware variants:
NSError * error = nil ;
NSString * serviceName = @"com.yourcompany.yourapp" ;
NSString * account = @"user@example.com" ;
NSString * password = @"mySecretPassword123" ;
// Save with error handling
BOOL success = [SAMKeychain setPassword: password
forService: serviceName
account: account
error: & error];
if ( ! success) {
if ([error code ] == errSecDuplicateItem) {
NSLog ( @"Password already exists" );
} else {
NSLog ( @"Error saving password: %@ " , [error localizedDescription ]);
}
}
// Retrieve with error handling
NSString * retrievedPassword = [SAMKeychain passwordForService: serviceName
account: account
error: & error];
if ( ! retrievedPassword && error) {
if ([error code ] == errSecItemNotFound) {
NSLog ( @"Password not found" );
} else {
NSLog ( @"Error retrieving password: %@ " , [error localizedDescription ]);
}
}
Error codes are defined in SecBase.h and include values like errSecItemNotFound, errSecDuplicateItem, and errSecAuthFailed. SAMKeychain also defines SAMKeychainErrorBadArguments for invalid parameters.
Setting Accessibility Type
For better security, always set the accessibility type to control when the keychain item can be accessed:
// Set accessibility type before saving passwords
[SAMKeychain setAccessibilityType: kSecAttrAccessibleWhenUnlocked ];
// Now save your password
[SAMKeychain setPassword: @"secret"
forService: @"MyApp"
account: @"user@example.com" ];
When Unlocked kSecAttrAccessibleWhenUnlockedRecommended for most apps. Data accessible only while device is unlocked.
After First Unlock kSecAttrAccessibleAfterFirstUnlockFor background apps. Data accessible after first unlock since boot.
Always kSecAttrAccessibleAlwaysData always accessible. Not recommended due to security concerns.
When Passcode Set kSecAttrAccessibleWhenPasscodeSetThisDeviceOnlyRequires device passcode. Highest security level.
Never use the default accessibility setting. It’s highly insecure. Always explicitly set the accessibility type.
Using SAMKeychainQuery
For more control over keychain operations, use SAMKeychainQuery:
NSError * error = nil ;
// Create a query
SAMKeychainQuery * query = [[SAMKeychainQuery alloc ] init ];
query.service = @"com.yourcompany.yourapp" ;
query.account = @"user@example.com" ;
query.password = @"mySecretPassword123" ;
// Save
BOOL success = [query save: & error];
if ( ! success) {
NSLog ( @"Save failed: %@ " , error);
}
// Fetch
SAMKeychainQuery * fetchQuery = [[SAMKeychainQuery alloc ] init ];
fetchQuery.service = @"com.yourcompany.yourapp" ;
fetchQuery.account = @"user@example.com" ;
if ([fetchQuery fetch: & error]) {
NSLog ( @"Password: %@ " , fetchQuery . password );
} else {
NSLog ( @"Fetch failed: %@ " , error);
}
// Delete
BOOL deleted = [fetchQuery deleteItem: & error];
Storing Binary Data
SAMKeychain can store binary data, not just strings:
// Create some binary data
NSData * tokenData = [ @"api-token-12345" dataUsingEncoding: NSUTF8StringEncoding ];
// Store binary data
[SAMKeychain setPasswordData: tokenData
forService: @"MyApp"
account: @"api-token" ];
// Retrieve binary data
NSData * retrievedData = [SAMKeychain passwordDataForService: @"MyApp"
account: @"api-token" ];
Storing Objects
With SAMKeychainQuery, you can store any object that conforms to NSCoding:
// Store a dictionary
NSDictionary * credentials = @{
@"username" : @"user@example.com" ,
@"token" : @"abc123" ,
@"expiry" : @"2026-12-31"
};
SAMKeychainQuery * query = [[SAMKeychainQuery alloc ] init ];
query.service = @"MyApp" ;
query.account = @"credentials" ;
query.passwordObject = credentials;
[query save: nil ];
// Retrieve the dictionary
SAMKeychainQuery * fetchQuery = [[SAMKeychainQuery alloc ] init ];
fetchQuery.service = @"MyApp" ;
fetchQuery.account = @"credentials" ;
if ([fetchQuery fetch: nil ]) {
NSDictionary * retrievedCredentials = ( NSDictionary * ) fetchQuery . passwordObject ;
NSLog ( @"Username: %@ " , retrievedCredentials [ @"username" ]);
}
Listing Accounts
You can retrieve all accounts stored in the keychain:
// Get all accounts across all services
NSArray * allAccounts = [SAMKeychain allAccounts ];
for ( NSDictionary * account in allAccounts) {
NSLog ( @"Account: %@ " , account [ kSAMKeychainAccountKey ]);
NSLog ( @"Service: %@ " , account [ kSAMKeychainWhereKey ]);
}
// Get accounts for a specific service
NSArray * accounts = [SAMKeychain accountsForService: @"com.yourcompany.yourapp" ];
for ( NSDictionary * account in accounts) {
NSLog ( @"Account: %@ " , account [ kSAMKeychainAccountKey ]);
}
Available dictionary keys:
kSAMKeychainAccountKey - Account name
kSAMKeychainWhereKey - Service name
kSAMKeychainLabelKey - Item label
kSAMKeychainCreatedAtKey - Creation date
kSAMKeychainLastModifiedKey - Last modified date
Complete Example
Here’s a complete example of a login manager using SAMKeychain:
#import <SAMKeychain/SAMKeychain.h>
@interface LoginManager : NSObject
+ ( void ) saveUsername: ( NSString * ) username password: ( NSString * ) password ;
+ ( NSDictionary * ) retrieveCredentials ;
+ ( void ) clearCredentials ;
@end
@implementation LoginManager
static NSString * const kServiceName = @"com.yourcompany.yourapp" ;
static NSString * const kAccountKey = @"currentUser" ;
+ ( void ) initialize {
// Set accessibility type once
[SAMKeychain setAccessibilityType: kSecAttrAccessibleWhenUnlocked ];
}
+ ( void ) saveUsername: ( NSString * ) username password: ( NSString * ) password {
NSError * error = nil ;
// Save password
BOOL success = [SAMKeychain setPassword: password
forService: kServiceName
account: username
error: & error];
if (success) {
// Save username to UserDefaults for quick access
[[ NSUserDefaults standardUserDefaults ] setObject: username forKey: @"username" ];
[[ NSUserDefaults standardUserDefaults ] synchronize ];
NSLog ( @"Credentials saved successfully" );
} else {
NSLog ( @"Failed to save credentials: %@ " , [error localizedDescription ]);
}
}
+ ( NSDictionary * ) retrieveCredentials {
NSString * username = [[ NSUserDefaults standardUserDefaults ] stringForKey: @"username" ];
if ( ! username) {
return nil ;
}
NSError * error = nil ;
NSString * password = [SAMKeychain passwordForService: kServiceName
account: username
error: & error];
if (password) {
return @{ @"username" : username, @"password" : password};
} else {
NSLog ( @"Failed to retrieve password: %@ " , [error localizedDescription ]);
return nil ;
}
}
+ ( void ) clearCredentials {
NSString * username = [[ NSUserDefaults standardUserDefaults ] stringForKey: @"username" ];
if (username) {
NSError * error = nil ;
[SAMKeychain deletePasswordForService: kServiceName
account: username
error: & error];
[[ NSUserDefaults standardUserDefaults ] removeObjectForKey: @"username" ];
[[ NSUserDefaults standardUserDefaults ] synchronize ];
NSLog ( @"Credentials cleared" );
}
}
@end
Usage:
// Save credentials
[LoginManager saveUsername: @"user@example.com" password: @"secret123" ];
// Retrieve credentials
NSDictionary * credentials = [LoginManager retrieveCredentials ];
if (credentials) {
NSLog ( @"Logged in as: %@ " , credentials [ @"username" ]);
}
// Clear credentials on logout
[LoginManager clearCredentials ];
Next Steps
Now that you understand the basics, explore more advanced features:
API Reference Complete API documentation for all methods and classes
Advanced Queries Learn about access groups, synchronization, and more
Common Patterns
NSString * accessToken = @"ya29.a0AfH6SMB..." ;
[SAMKeychain setPassword: accessToken
forService: @"com.yourapp.oauth"
account: @"google-access-token" ];
[SAMKeychain setPassword: @"sk_live_abc123"
forService: @"com.yourapp"
account: @"stripe-api-key" ];
Checking if Password Exists
NSString * password = [SAMKeychain passwordForService: @"MyApp"
account: @"user@example.com" ];
if (password) {
NSLog ( @"Password exists" );
} else {
NSLog ( @"No password found" );
}
Updating an Existing Password
// SAMKeychain automatically updates if a password already exists
[SAMKeychain setPassword: @"newPassword"
forService: @"MyApp"
account: @"user@example.com" ];