Skip to content

Instantly share code, notes, and snippets.

@mlapointe
Last active May 3, 2018 13:24
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mlapointe/6e88a9f059f1cc0dabec to your computer and use it in GitHub Desktop.
Save mlapointe/6e88a9f059f1cc0dabec to your computer and use it in GitHub Desktop.
KeychainHelper - Simple Keychain access for iOS Keychain Services
//
// KeychainHelper.h
#import <Foundation/Foundation.h>
@interface KeychainHelper : NSObject
@property (strong, nonatomic) NSMutableDictionary * keychainItem;
- (void)saveKeychainWithEmail:(NSString *)email andToken: (NSString *)token;
- (NSString *)getAuthToken;
- (NSString *)getEmail;
@end
//
// KeychainHelper.m
#import "KeychainHelper.h"
#import <Security/Security.h>
@interface KeychainHelper ()
@end
static const NSString * WEBSITE = @"www.yoursite.com";
@implementation KeychainHelper
- (NSMutableDictionary *)createEmptyKeychainItem{
//Let's create an empty mutable dictionary:
_keychainItem = [NSMutableDictionary dictionary];
//Populate it with the data and the attributes we want to use.
_keychainItem[(__bridge id)kSecClass] = (__bridge id)kSecClassInternetPassword; // We specify what kind of keychain item this is.
_keychainItem[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleWhenUnlocked; // This item can only be accessed when the user unlocks the device.
_keychainItem[(__bridge id)kSecAttrServer] = WEBSITE;
_keychainItem[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanTrue;
_keychainItem[(__bridge id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue;
return nil;
}
- (void)saveKeychainWithEmail: (NSString *) email andToken: (NSString *)token{
[self createEmptyKeychainItem];
//Check if this keychain item already exists.
if(SecItemCopyMatching((__bridge CFDictionaryRef)_keychainItem, NULL) == noErr)
{
//Item Already Exists == Update instead
[self updateKeychainItemWithEmail:email andToken:token];
} else {
//Item does not exist -- create new
_keychainItem[(__bridge id)kSecValueData] = [token dataUsingEncoding:NSUTF8StringEncoding];
_keychainItem[(__bridge id)kSecAttrAccount] = email;
OSStatus sts = SecItemAdd((__bridge CFDictionaryRef)_keychainItem, NULL);
NSLog(@"Error Code: %d", (int)sts);
}
}
- (void)updateKeychainItemWithEmail:(NSString *)email andToken:(NSString *)token{
NSMutableDictionary *attributesToUpdate = [NSMutableDictionary dictionary];
attributesToUpdate[(__bridge id)kSecValueData] = [token dataUsingEncoding:NSUTF8StringEncoding];
attributesToUpdate[(__bridge id)kSecAttrAccount] = email;
//Must set these back to false for SecItemUpdate to work
_keychainItem[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanFalse;
_keychainItem[(__bridge id)kSecReturnAttributes] = (__bridge id)kCFBooleanFalse;
OSStatus sts = SecItemUpdate((__bridge CFDictionaryRef)_keychainItem, (__bridge CFDictionaryRef)attributesToUpdate);
NSLog(@"Error Code: %d", (int)sts);
}
- (NSString *)getAuthToken{
CFDictionaryRef result = nil;
[self createEmptyKeychainItem];
OSStatus sts = SecItemCopyMatching((__bridge CFDictionaryRef)_keychainItem, (CFTypeRef *)&result);
NSLog(@"Error Code: %d", (int)sts);
if(sts == noErr)
{
NSDictionary *resultDict = (__bridge_transfer NSDictionary *)result;
NSData *tokenData = resultDict[(__bridge id)kSecValueData];
NSString *token = [[NSString alloc] initWithData:tokenData encoding:NSUTF8StringEncoding];
return token;
}else
{
NSLog(@"No Keychain found for user");
return nil;
}
}
- (NSString *)getEmail{
CFDictionaryRef result = nil;
[self createEmptyKeychainItem];
OSStatus sts = SecItemCopyMatching((__bridge CFDictionaryRef)_keychainItem, (CFTypeRef *)&result);
NSLog(@"Error Code: %d", (int)sts);
if(sts == noErr)
{
NSDictionary *resultDict = (__bridge_transfer NSDictionary *)result;
return resultDict[(__bridge id)kSecAttrAccount];
;
}else
{
NSLog(@"No Keychain found for user");
return nil;
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment