Last active
May 29, 2024 18:33
-
-
Save mlapointe/6e88a9f059f1cc0dabec to your computer and use it in GitHub Desktop.
KeychainHelper - Simple Keychain access for iOS Keychain Services
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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