Protecting data with Touch ID is a great way to improve your app.
Let's take a look at how to do it:
Save to Keychain
First you need to save something to the keychain, and protect it with the User Presence access control flag.
func savePassword(username: String, password: String) {
let passwordData = password.dataUsingEncoding(NSUTF8StringEncoding)
guard let data = passwordData else { return }
let accessControl = SecAccessControlCreateWithFlags(
kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
.UserPresence // this part enables Touch ID support
, nil
)
SecItemAdd([
String(kSecAttrService) : serviceID,
String(kSecClass) : kSecClassGenericPassword,
String(kSecAttrAccessControl) : accessControl.takeUnretainedValue(),
String(kSecAttrAccount) : username,
String(kSecValueData) : data
], nil)
}
Retrieve From Keychain
Then when you retrieve, supply a prompt message and iOS will show the familiar Touch ID alert before executing the Keychain query:
func passwordForUsername(username: String) -> String? {
let query = [
String(kSecAttrService) : serviceID,
String(kSecClass) : kSecClassGenericPassword,
String(kSecReturnData) : true,
String(kSecMatchLimit) : kSecMatchLimitOne,
String(kSecUseOperationPrompt) : "Authenticate to Login",
String(kSecAttrAccount) : username
]
// Working with the Security Framework is still kind of ugly in Swift:
var passwordData: Unmanaged<AnyObject>? = nil
SecItemCopyMatching(query, &passwordData)
if let opaque = passwordData?.toOpaque() {
return NSString(
data: Unmanaged<NSData>.fromOpaque(opaque).takeUnretainedValue(),
encoding: NSUTF8StringEncoding
) as? String
}
return nil
}