Delete keychain items when an app is uninstalled

118,105

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);
        }
Share:
118,105

Related videos on Youtube

enc
Author by

enc

Updated on December 15, 2020

Comments

  • enc
    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
      Jonathan Grynspan over 13 years
      Since your code doesn't run when your application is being deleted, you have no way of doing this.
  • XCool
    XCool almost 13 years
    I 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
    Amro over 10 years
    NSUserDefaults 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
    Amro over 10 years
    You'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
    Amro over 10 years
    P.S. And here's an article that explains it in detail chrisrisner.com/…
  • stephen
    stephen over 10 years
    Oh...you are right. Sorry. Hard to find the test code in 800 files. I'll update my answer.
  • Aurelien Porte
    Aurelien Porte almost 10 years
    I 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ář
    Jakub Truhlář about 7 years
    It was until beta 5 i guess, public release of iOS 10.3 does not contain this change.
  • nefarianblack
    nefarianblack about 6 years
    if !userDefaults.bool(forKey: "hasRunBefore") { It is just cleaner.
  • Pochi
    Pochi almost 6 years
    The synchronize call should be removed.
  • Moaz Saeed
    Moaz Saeed over 5 years
    So, If we change provisioning profile of our application, would it be able to access previously stored values in keychain.
  • Christopher Stephan
    Christopher Stephan almost 5 years
    By using if (VersionTracking.IsFirstLaunchEver) {// remove keychain items} from Xamarin.Essentials you do not need the code for the userDefaults. Xamarin.Essentials wraps that for you.
  • theoriginalbit
    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 the UserDefaults (which clears on app uninstall) states the app has not been previously run, but the keychain contains items, you can delete the items.
  • CharlesA
    CharlesA almost 4 years
    Or even if !UserDefaults.standard.bool(forKey: "FirstInstall") which defaults to false if the key doesn't exist. And .synchronize() not needed.
  • ricardopereira
    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
    cglacet over 2 years
    Can 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.