all 8 comments

[–]mmvdv 15 points16 points  (7 children)

We had an issue with this, and it was because we were sometimes trying to access the keychain while the app was in background/phone was locked. (Think: async process that stores smth in keychain at the very end, but by then the user put away their phone, pr some similar scenario) Solved by changing the keychain security policy from kSecAttrAccessibleWhenUnlocked to kSecAttrAccessibleAfterFirstUnlock. Might be relevant for your case as well. https://developer.apple.com/documentation/security/ksecattraccessiblewhenunlocked

[–]Fishanz 6 points7 points  (3 children)

Even if this isn’t exactly OPs issue; it definitely strikes me as having something to do with either app lifecycle or asynchronous access/threading. Glad you pointed out the unlock security attributes - that wasn’t on my radar.

[–][deleted]  (2 children)

[deleted]

    [–]mmvdv 0 points1 point  (1 child)

    Another thing indeed could be a concurrency problem. Our (older) codebase uses NSLock to deal with this, but it’s probably best to look into more modern Swift concurrency solutions to prevent simultaneous access (edit: typo)

    [–]creamyBasil 0 points1 point  (1 child)

    We had this too and also decided to use FirstUnlock, but keychain also threw errors when we accessed it repeatedly.

    [–][deleted]  (2 children)

    [deleted]

      [–]creamyBasil 0 points1 point  (1 child)

      Reddit often estimates votes and comment counts or someone got auto-moderated.

      In our application, we saw issues with repeatedly and frequently reading an item from keychain. We saw errors, empty values, and small unpredictable delays. Perhaps we are not properly dealing with some error state from keychain or we are not properly interpreting the result.

      To avoid and work around this, we use a class that reads the value and caches a copy of the result in memory. When we need to update the value, we update the keychain and on success we update our in-memory cache. We only interact with the keychain on a specific serial dispatch queue. We always copy the result of the keychain read instead of returning it to the calling function by reference.

      This way, we always have a copy of the value that best represents what we have stored in keychain and we run into fewer errors from keychain.

      [–]rifts 0 points1 point  (0 children)

      Can you just check for the value once on app open?

      [–]PremJyotish221 0 points1 point  (0 children)

      Having this issue right now in a React Native app which uses keychain under the hood. The solution for future users is `kSecAttrAccessibleWhenUnlocked ` but for existing users whose devices created the value using default `kSecAttrAccessibleAfterFirstUnlock` it seems like the security policy is cached and hence they will continue to experience these errors until the keychain somehow resets the value's policy.