We have been struggling with a sporadic issue in our iOS app for some time now, where it seems that occasionally our application will be launched and the keychain is not yet accessible. We have not found a way to reproduce this reliably.
As do many apps, we save some sensitive data (i.e., user credentials) to the keychain using kSecAttrAccessible = kSecAttrAccessibleWhenUnlocked. The app will read those values from the keychain during startup in the didFinishLaunchingWithOptions override of our app delegate. This works fine the large majority of the time.
But sometimes our users will report problems that indicate that the keychain values could not be read. If the user simply kills the app and restarts it, the values are still there and everything is working as normal. Our application does not run in the background, so I can't think of a case where it is started by anything other than a user action, which would mean the device is unlocked.
I am familiar with the applicationProtectedDataDidBecomeAvailable method, which is called by the OS when a device is unlocked and protected data like the keychain becomes accessible. I suppose we could check in didFinishLaunchingWithOptions if UIApplication.isProtectedDataAvailable is false, and if so defer the part of the app initialization that depends on the keychain to happen in the applicationProtectedDataDidBecomeAvailable method. I'm just always leery of coding a solution without being able to reproduce and test it.
Can anyone report that they have seen instances via app logs where the iOS protected data is not yet available in the didFinishLaunchingWithOptions method, but becomes available later?
With iOS 10.3.2 release I am seeing instances where it is randomly happening to some of my users as well. Our OAuth credentials are stored in Keychain which is accessed every time an API call is made. If OAuth does not exist I logout the user as we have sensitive data on the device.
I have a check for isProtectedDataAvailable
on background refresh so I know it is not queuing up any API calls then.
Like you I really don't want to add a check/wait for protected data to be available on foreground. It defeats the purpose of having kSecAttrAccessibleWhenUnlocked
Here is one recent issue posted with regards to Keychain which suggests decryption time could be another culprit. https://github.com/evgenyneu/keychain-swift/issues/15
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With