Hi everyone,
I’m encountering an unexpected Keychain behavior in a production environment and would like to confirm whether this is expected or if I’m missing something.
In my app, I store a deviceId in the Keychain based on the classic KeychainItemWrapper implementation. I extended it by explicitly setting:
kSecAttrAccessible = kSecAttrAccessibleAfterFirstUnlock
My understanding is that kSecAttrAccessibleAfterFirstUnlock should allow Keychain access while the app is running in the background, as long as the device has been unlocked at least once after reboot.
However, after the app went live, I observed that when the app performs background execution (e.g., triggered by background tasks / silent push), Keychain read attempts intermittently fail with:
errSecInteractionNotAllowed (-25308)
This seems inconsistent with the documented behavior of kSecAttrAccessibleAfterFirstUnlock.
Additional context:
The issue never occurs in foreground.
The issue does not appear on development devices.
User devices are not freshly rebooted when this happens.
The Keychain item is created successfully; only background reads fail.
Setting the accessibility to kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly produces the same result.
Questions:
Under what circumstances can kSecAttrAccessibleAfterFirstUnlock still cause a -25308 error?
Is there any known restriction when accessing Keychain while the app is running in background execution contexts?
Could certain system states (Low Power Mode, Background App Refresh conditions, device lock state, etc.) cause Keychain reads to be blocked unexpectedly?
Any insights or similar experiences would be greatly appreciated. Thank you!
kSecAttrAccessibleAfterFirstUnlock should allow [access] as long as the device has been unlocked at least once after reboot.
Correct.
I’m aware of two common causes of this problem:
- There are very limited circumstances under which iOS will run third-party code before first unlock. The canonical example of this is VoIP push notifications.
- Sometimes these problems are caused by the keychain item not having the correct
kSecAttrAccessiblevalue. For example, where the developer shipped a version of their app that set the attribute incorrectly and fixed that in the next version, which left any user who first ran the broken version of their app with the wrong value.
Beyond that, it’s hard to say what’s going on here. It’s certainly possible to imagine an OS-level bug causing a problem like this, but I’m not aware of any such bug in play right now.
I have general advice about how to approach issues like this in Investigating hard-to-reproduce keychain problems.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"