Using the Keychain to store passwords on iOS

Guides | Tutorial By 5 years ago

When people need to save a password or any other type of sensitive information in an iOS app I see them way too often just storing it in plain text in the NSUserDefaults. This is bad bad bad. Some other times people will try and implement their own encryption or ciphering to hide the real information, but there is no need. From OS X, the iOS implements the keychain. This is Apple’s way of storing things securely for you, and it’s dead easy so there’s no need to store things insecurely.

If you do everything from scratch then it can be a bit of code, but Apple has a keychain wrapper class, download the KeychainItemWrapper.h and KeychainItemWrapper.m from Apple’s site. You will also need to link your project with the Security framework.

This wrapper is similar to an NSDictionary, you set values for keys, however you don’t get to choose the keys and there are a couple of other methods to take into consideration.

The main keys you will need to work with are as follows:

This holds account information, something like an email address or username

This is for the secure data. Passwords, session keys, anything of the sort

When the information above is available. You must specify one of the following: kSecAttrAccessibleWhenUnlocked, kSecAttrAccessibleAfterFirstUnlock, kSecAttrAccessibleAlways, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly and kSecAttrAccessibleAlwaysThisDeviceOnly.

For most applications kSecAttrAccessibleWhenUnlocked is probably the best option, which means the information is only available when the device is unlocked and will be transferred between backups to other devices

Now you know the basics, it’s time to use this keychain wrapper. The identifier should be unique per keychain item, two different identifiers will represent two different bits of information. The access group can be nil unless you want to share this keychain item among multiple apps.

KeychainItemWrapper* keychain = [[KeychainItemWrapper alloc] initWithIdentifier:@"KeychainTest" accessGroup:nil];
[keychain setObject:kSecAttrAccessibleWhenUnlocked forKey:kSecAttrAccessible];

NSLog(@"%@, %@", [keychain objectForKey:kSecAttrAccount], [keychain objectForKey:kSecValueData]);

[keychain setObject:@"" forKey:kSecAttrAccount];
[keychain setObject:@"MySuperSecretPassword" forKey:kSecValueData];

[keychain release];
keychain = nil;

The first time you run this there will be no entries for the account and data fields, run it again and you will get the information from the previous time. When the user logs out or you need to clear the data, call [keychain resetKeychainItem];

  • bhaskar jyoti choudhury

    Could you write a simple code to retrieve the username and password back from the keychain

    • Tom

      See the line in my code above:
      NSLog(@”%@, %@”, [keychain objectForKey:kSecAttrAccount], [keychain objectForKey:kSecValueData]);

      This is how you get the username/password back. The first time you run the code above it will show nothing, then the second time (after it’s been set) it will show, MySuperSecretPassword

  • Rob Wilco

    Wonderful – thank you for such an elegant explanation! It’s the sort of thing you wonder how you ever got along without.

    There is a glitch that I have run into – only under iOS 7 – and it concerns kSecAttrAccessible’s default value leading to forced logouts.

    This blog post explains it fairly well:

    What is troubling me, however, is what I see in SecItem.h (in conjunction with their chosen workaround). It works beautifully, but when I see “This is not recommended for anything except system use” in the header, I start to wonder … 😮


    • Tom

      I don’t know how accurate that blog post is, however to find out you could post on the Apple dev forums, where often you will get an Apple engineer reply to you with information that may help you out.

  • Great article, I’m just wondering what to add to this code in order to make it sync-able between devices. Thanks!

  • Jim Rota

    I agree, good article. I’ve read that keychain storage is a good option for securing inApp purchases. Can I use kSecAttrAccount for this? i.e., can it be used to store several items or just ONE (i.e. username)?

  • sreedeep paul

    On iOS8 when I am trying to set the kSecAttrAccessible key before setting my object .I am facing an Assertion failure crash.
    KeychainItemWrapper* keychain = [[KeychainItemWrapper alloc] initWithIdentifier:@”KeychainTest” accessGroup:nil];
    [keychain setObject:kSecAttrAccessibleWhenUnlocked forKey:kSecAttrAccessible];
    [keychain setObject:@”MySuperSecretPassword” forKey:kSecValueData];
    The assertion failure is due to SecItemUpdate() returning a status of -50, which appears to be a generic “invalid parameters” error?

  • Carlos Perez

    You definitely saved my life. I was fighting with NSInternalInconsistencyException for hours until I found kSecAttrAccessibleAlways !!!
    Thank you!!