I am currently trying to enable users of my app to add and retrieve data from the keychain using biometric authentication. When adding an item to the keychain, the call to SecItemAdd returns successful status, but when retrieving an item from the keychain via SecItemCopyMatching I get the -50 OSStatus (errSecParam), which indicates that one of my parameters are wrong.
When debugging, I removed either the kSecAttrAccessControl or kSecAttrAccessible parameters from the query, which got rid of the error. However, now I am faced with a different issue the system is retrieving the value from the keychain without first prompting the user.
Code that either results in an errSecParam (-50) result or no authentication prompt:
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: "MyApp",
kSecAttrAccount as String: "BiometricLogin",
// removing this key from the SecItemCopyMatching query gets rid of the error but results in no authentication prompt
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
kSecReturnAttributes as String: kCFBooleanTrue,
kSecReturnData as String: kCFBooleanTrue,
// removing this key from the SecItemCopyMatching query gets rid of the error but results in no authentication prompt
kSecAttrAccessControl as String: SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, .biometryCurrentSet, nil)!,
kSecUseAuthenticationUI as String: kSecUseAuthenticationUIAllow,
kSecUseOperationPrompt as String: "Authenticate with Biometrics"
]
let addQuery = query.merging([(kSecValueData as String, "Hi".data(encoding: .utf8)!)], uniquingKeysWith: { $1 })
let status = SecItemAdd(query as CFDictionary, nil)
print(status) // prints 0, success
let retrieveQuery = query
var queryResult: AnyObject?
let status = SecItemCopyMatching(retrieveQuery as CFDictionary, &queryResult)
print(status) // prints -50 if both kSecAttrAccessible and kSecAttrAccessControl are in the query, and prints 0 if either of those attributes are removed but the result is no authentication prompt
So my question is: How can I get the user to be prompted with an authentication prompt to retrieve data from the keychain? To reiterate, I am using kSecClassGenericPassword, kSecAttrAccessibleWhenUnlockedThisDeviceOnly and .biometryCurrentSet.