iOS: How to store username/password within an app?
IosNsuserdefaultsKeychainIos Problem Overview
I have a login-screen in my iOS app.
The username and password will be saved in the NSUserDefaults
and be loaded into the login-screen again when you enter the app again (of course, NSUserDefaults
are permanent).
Now, the user have the possibility to disable the username/password saving feature.
So the NSUserDefaults
will be cleared then.
But In my app I need this username/password for database queries for the user.
So: Where to store the data except NSUserDefaults
?
(This place can / should be deleted when the user quit the app or logout).
Ios Solutions
Solution 1 - Ios
You should always use Keychain to store usernames and passwords, and since it's stored securely and only accessible to your app, there is no need to delete it when app quits (if that was your concern).
Apple provides sample code that stores, reads and deletes keychain items and here is how to use the keychain wrapper class from that sample which greatly simplifies using Keychain.
Include Security.framework (in Xcode 3 right-click on frameworks folder and add existing framework. In Xcode 4 select your project, then select target, go to Build Phases tab and click + under Link Binary With Files) and KeychainItemWrapper .h & .m files into your project, #import the .h file wherever you need to use keychain and then create an instance of this class:
KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];
(YourAppLogin can be anything you chose to call your Keychain item and you can have multiple items if required)
Then you can set the username and password using:
[keychainItem setObject:@"password you are saving" forKey:kSecValueData];
[keychainItem setObject:@"username you are saving" forKey:kSecAttrAccount];
Get them using:
NSString *password = [keychainItem objectForKey:kSecValueData];
NSString *username = [keychainItem objectForKey:kSecAttrAccount];
Or delete them using:
[keychainItem resetKeychainItem];
Solution 2 - Ios
If you need an ARC version of the wrapper here is the link https://gist.github.com/1170641 Thanks to
Solution 3 - Ios
A very easy solution via Keychains.
It's a simple wrapper for the system Keychain. Just add the SSKeychain.h
, SSKeychain.m
, SSKeychainQuery.h
and SSKeychainQuery.m
files to your project and add the Security.framework to your target.
To save a password:
[SSKeychain setPassword:@"AnyPassword" forService:@"AnyService" account:@"AnyUser"]
To retrieve a password:
NSString *password = [SSKeychain passwordForService:@"AnyService" account:@"AnyUser"];
Where setPassword
is what value you want saved and forService
is what variable you want it saved under and account is for what user/object the password and any other info is for.
Solution 4 - Ios
You can simply use NSURLCredential
, it will save both username and password in the keychain in just two lines of code.
See my detailed answer.
Solution 5 - Ios
I decided to answer how to use keychain in iOS 8 using Obj-C and ARC.
1)I used the keychainItemWrapper (ARCifief version) from GIST: https://gist.github.com/dhoerl/1170641/download
- Add (+copy) the KeychainItemWrapper.h and .m to your project
-
Add the Security framework to your project (check in project > Build phases > Link binary with Libraries)
-
Add the security library (#import
) and KeychainItemWrapper (#import "KeychainItemWrapper.h") to the .h and .m file where you want to use keychain. -
To save data to keychain:
NSString *emailAddress = self.txtEmail.text; NSString *password = self.txtPasword.text; //because keychain saves password as NSData object NSData *pwdData = [password dataUsingEncoding:NSUTF8StringEncoding];
//Save item self.keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil]; [self.keychainItem setObject:emailAddress forKey:(__bridge id)(kSecAttrAccount)]; [self.keychainItem setObject:pwdData forKey:(__bridge id)(kSecValueData)];
-
Read data (probably login screen on loading > viewDidLoad):
self.keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];
self.txtEmail.text = [self.keychainItem objectForKey:(__bridge id)(kSecAttrAccount)];
//because label uses NSString and password is NSData object, conversion necessary NSData *pwdData = [self.keychainItem objectForKey:(__bridge id)(kSecValueData)]; NSString *password = [[NSString alloc] initWithData:pwdData encoding:NSUTF8StringEncoding]; self.txtPassword.text = password;
Enjoy!
Solution 6 - Ios
If you are having an issue retrieving the password using the keychain wrapper, use this code:
NSData *pass =[keychain objectForKey:(__bridge id)(kSecValueData)];
NSString *passworddecoded = [[NSString alloc] initWithData:pass
encoding:NSUTF8StringEncoding];
Solution 7 - Ios
checkout this sample code i tried first the apple's wrapper from the sample code but this is much simpler for me
Solution 8 - Ios
try this one:
KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];
[keychainItem setObject:@"password you are saving" forKey:kSecValueData];
[keychainItem setObject:@"username you are saving" forKey:kSecAttrAccount];
may it will help.
Solution 9 - Ios
I looked at using KeychainItemWrapper (the ARC version) but I didn't find its Objective C wrapper as wholesome as desired.
I used this solution by Kishikawa Katsumi, which meant I wrote less code and didn't have to use casts to store NSString values.
Two examples of storing:
[UICKeyChainStore setString:@"kishikawakatsumi" forKey:@"username"];
[UICKeyChainStore setString:@"P455_w0rd$1$G$Z$" forKey:@"password"];
Two examples of retrieving
UICKeyChainStore *store = [UICKeyChainStore keyChainStore];
// or
UICKeyChainStore *store = [UICKeyChainStore keyChainStoreWithService:@"YOUR_SERVICE"];
NSString *username = [store stringForKey:@"username"];
NSString *password = [store stringForKey:@"password"];
Solution 10 - Ios
There is a small bug in the above code (by the way Dave it was very helpful your post thank you)
In the part where we save the credentials it also needs the following code in order to work properly.
[self.keychainItem setObject:@"myCredentials" forKey:(__bridge id)(kSecAttrService)];
most probably is because the second time we try to (re-)sign in with the same credentials it finds them already assigned in the keychain items and the app crashes. with the above code it works like a charm.
Solution 11 - Ios
To update this question:
For those using Swift checkout this drag and drop swift implementation by Mihai Costea supporting access groups:
https://github.com/macostea/KeychainItemWrapper.swift/blob/master/KeychainItemWrapper.swift
Before using the keychain: consider twice before storing passwords. In many cases storing an authentication token (such as a persistence session id) and the email or account name might be enough. You can easily invalidate authentication tokens to block unauthorized access, requiring the user to login again on the compromised device but not requiring reset password and having to login again on all devices (we are not only using Apple are we?).
Solution 12 - Ios
But, now you can go for NURLCredential instead of keychain wrapper. It does what we need to do.
Solution 13 - Ios
For swift you can use this library:
https://github.com/jrendel/SwiftKeychainWrapper
It supports all versions of swift.
Solution 14 - Ios
The following should work just fine:
KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];
[keychainItem setObject:@"password you are saving" forKey:kSecValueData];
[keychainItem setObject:@"username you are saving" forKey:kSecAttrAccount];
Solution 15 - Ios
If your app has an associated domain it's better to use Managing Shared Credentials. It will provide the best experience for the user and it's managed by the system itself.
Step 1:
Set up your Associated Domains with webcredentials key
Step 2
Mark your text fields
userIdTextField.textContentType = .username
passwordTextField.textContentType = .password
Step 3
Use the following code to save the details whenever the user successfully login. iOS will show a confirmation action sheet for the user to save the password. And next time the user tries to login keyboard will suggest the user credentials for your app.
SecAddSharedWebCredential("www.example.com" as CFString, "user_id" as CFString, "password" as CFString) { error in
if error != nil {
// Handle error
return
}
// The credentials have been successfully saved.
}
Now you're ready to go. Read more...?!