Delete keychain items when an app is uninstalled
Solution 1
You can take advantage of the fact that NSUserDefaults
are cleared by uninstallation of an app. For example:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Clear keychain on first run in case of reinstallation
if (![[NSUserDefaults standardUserDefaults] objectForKey:@"FirstRun"]) {
// Delete values from keychain here
[[NSUserDefaults standardUserDefaults] setValue:@"1strun" forKey:@"FirstRun"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
//...Other stuff that usually happens in didFinishLaunching
}
This checks for and sets a "FirstRun" key/value in NSUserDefaults
on the first run of your app if it's not already set. There's a comment where you should put code to delete values from the keychain. Synchronize can be called to make sure the "FirstRun" key/value is immediately persisted in case the user kills the app manually before the system persists it.
Solution 2
For users looking for a Swift 3.0 version of @amro's answer:
let userDefaults = UserDefaults.standard
if !userDefaults.bool(forKey: "hasRunBefore") {
// Remove Keychain items here
// Update the flag indicator
userDefaults.set(true, forKey: "hasRunBefore")
}
*note that synchronize() function is deprecated
Solution 3
There is no trigger to perform code when the app is deleted from the device. Access to the keychain is dependant on the provisioning profile that is used to sign the application. Therefore no other applications would be able to access this information in the keychain.
It does not help with you aim to remove the password in the keychain when the user deletes application from the device but it should give you some comfort that the password is not accessible (only from a re-install of the original application).
Solution 4
For those looking for a Swift version of @amro's answer:
let userDefaults = NSUserDefaults.standardUserDefaults()
if userDefaults.boolForKey("hasRunBefore") == false {
// remove keychain items here
// update the flag indicator
userDefaults.setBool(true, forKey: "hasRunBefore")
userDefaults.synchronize() // forces the app to update the NSUserDefaults
return
}
Solution 5
C# Xamarin version
const string FIRST_RUN = "hasRunBefore";
var userDefaults = NSUserDefaults.StandardUserDefaults;
if (!userDefaults.BoolForKey(FIRST_RUN))
{
//TODO: remove keychain items
userDefaults.SetBool(true, FIRST_RUN);
userDefaults.Synchronize();
}
... and to clear records from the keychain (TODO comment above)
var securityRecords = new[] { SecKind.GenericPassword,
SecKind.Certificate,
SecKind.Identity,
SecKind.InternetPassword,
SecKind.Key
};
foreach (var recordKind in securityRecords)
{
SecRecord query = new SecRecord(recordKind);
SecKeyChain.Remove(query);
}
Related videos on Youtube
enc
Updated on December 15, 2020Comments
-
enc over 3 years
I am using idandersen's scifihifi-iphone code for keychain and save password using
[SFHFKeychainUtils storeUsername:@"User" andPassword:@"123" forServiceName:@"TestService" updateExisting:YES error:&error];
When I delete the application from the device, the password remains in the keychain.
I want to remove the password from the keychain when the user deletes the application from the device. How can I do this?
-
Jonathan Grynspan over 13 yearsSince your code doesn't run when your application is being deleted, you have no way of doing this.
-
-
XCool almost 13 yearsI agree with Amro that you can delete/purge your keychain upon the first run of the application. This will clear out everything that was set prior to the app being uninstalled the last time. I did this for one of my apps that stores Facebook/Twitter credentials and it's been working pretty well knowing the fact that only your app has access to whatever keychain that was set.
-
Amro over 10 yearsNSUserDefaults are not cleared when the user manually quits the app. Only values that you've set but either the system (periodically) or you have not yet synchronized with the disk (by calling
synchronize
) are lost in that case. It's a good idea to call synchronize after setting the first run key. And yes, NSUserDefaults are cleared when a device is reset (and not restored from backup), and that's fine in this case. -
Amro over 10 yearsYou're wrong and you're probably doing something that's causing user defaults to be cleared. The entire point of NSUserDefaults is to save preferences and have those preferences persist through multiple application launches. Again, resetting the device or deleting an app will remove user defaults. Look at how many people have up-voted this answer and check your code. Then go read the documentation. Heck, send me the relevant code and I'll show you what you're doing wrong. It's been this way since iOS 2.0. Down vote away but I'd suggest writing an isolated, simple, test case first.
-
Amro over 10 yearsP.S. And here's an article that explains it in detail chrisrisner.com/…
-
stephen over 10 yearsOh...you are right. Sorry. Hard to find the test code in 800 files. I'll update my answer.
-
Aurelien Porte almost 10 yearsI would not be very confident on using NSUserDefault for this. Why? Have a look at that thread: stackoverflow.com/questions/20269116/…. If you start your app from the background, there are cases where your custom keys in NSUserDefaults are just not set. Applying this answer would lead to delete your Keychain custom keys although you really didn't want that!
-
Jakub Truhlář about 7 yearsIt was until beta 5 i guess, public release of iOS 10.3 does not contain this change.
-
nefarianblack about 6 years
if !userDefaults.bool(forKey: "hasRunBefore") {
It is just cleaner. -
Pochi almost 6 yearsThe synchronize call should be removed.
-
Moaz Saeed over 5 yearsSo, If we change provisioning profile of our application, would it be able to access previously stored values in keychain.
-
Christopher Stephan almost 5 yearsBy using
if (VersionTracking.IsFirstLaunchEver) {// remove keychain items}
from Xamarin.Essentials you do not need the code for theuserDefaults
. Xamarin.Essentials wraps that for you. -
theoriginalbit almost 5 years@AugustinePA they're not suggesting saving user credentials into
UserDefaults
. They're suggesting to store a flag that specifies whether the app has previously been run. That way if theUserDefaults
(which clears on app uninstall) states the app has not been previously run, but the keychain contains items, you can delete the items. -
CharlesA almost 4 yearsOr even
if !UserDefaults.standard.bool(forKey: "FirstInstall")
which defaults to false if the key doesn't exist. And .synchronize() not needed. -
ricardopereira about 3 years@MoazSaeed from my experience, the app have access to previously stored values in Keychain even if the provisioning profile changes.
-
cglacet over 2 yearsCan the user remove these flags in any way? (For example by deleting app cached data etc.). If yes then this would also delete keychain values which looks like an undesirable side effect.