Delete keychain items when an app is uninstalled

IosObjective CKeychain

Ios Problem Overview


I am using http://log.scifihifi.com/post/55837387/simple-iphone-keychain-code">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?

Ios Solutions


Solution 1 - Ios

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 - Ios

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 - Ios

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 - Ios

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 - Ios

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);
		}

Solution 6 - Ios

Files will be deleted from your app's document directory when the user uninstalls the app. Knowing this, all you have to do is check whether a file exists as the first thing that happens in application:didFinishLaunchingWithOptions:. Afterwards, unconditionally create the file (even if it's just a dummy file).

If the file did not exist at time of check, you know this is the first run since the latest install. If you need to know later in the app, save the boolean result to your app delegate member.

Solution 7 - Ios

@amro's answer translated to Swift 4.0:

if UserDefaults.standard.object(forKey: "FirstInstall") == nil {
    UserDefaults.standard.set(false, forKey: "FirstInstall")
    UserDefaults.standard.synchronize()
}

Solution 8 - Ios

This seems to be the default behavior on iOS 10.3 based on behavior people have been witnessing in beta #2. Haven't found any official documentation about this yet so please comment if you have.

Solution 9 - Ios

Just add an app setting bundle and implement a toggle to reset the keychain on app restart or something based on the value selected through settings (available through userDefaults)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionencView Question on Stackoverflow
Solution 1 - IosAmroView Answer on Stackoverflow
Solution 2 - IosbwcView Answer on Stackoverflow
Solution 3 - IosShane FitzgibbonView Answer on Stackoverflow
Solution 4 - IosrscView Answer on Stackoverflow
Solution 5 - IosInquisitorJaxView Answer on Stackoverflow
Solution 6 - IosstephenView Answer on Stackoverflow
Solution 7 - IosMuhammad NayabView Answer on Stackoverflow
Solution 8 - IosStavashView Answer on Stackoverflow
Solution 9 - IosUmar CheemaView Answer on Stackoverflow