Skip to main content
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.
1

Import SAMKeychain

Add the import statement to your source file:
#import <SAMKeychain/SAMKeychain.h>
2

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.
3

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");
}
4

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"];
NSString *password = [SAMKeychain passwordForService:@"MyApp" 
                                             account:@"user@example.com"];
if (password) {
    NSLog(@"Password exists");
} else {
    NSLog(@"No password found");
}
// SAMKeychain automatically updates if a password already exists
[SAMKeychain setPassword:@"newPassword" 
              forService:@"MyApp" 
                 account:@"user@example.com"];

Build docs developers (and LLMs) love