Implement Face ID authentication and update iOS configuration for biometric support
This commit is contained in:
21
docs/IOS_BIOMETRICS.md
Normal file
21
docs/IOS_BIOMETRICS.md
Normal file
@@ -0,0 +1,21 @@
|
||||
iOS Biometric / Device Lock Setup
|
||||
|
||||
To enable and test device biometric authentication on iOS:
|
||||
|
||||
- Ensure the Info.plist contains a Face ID usage description (`NSFaceIDUsageDescription`). This project already adds a default string.
|
||||
- Install CocoaPods and native deps:
|
||||
|
||||
```sh
|
||||
cd ios
|
||||
bundle install # (if you use Bundler)
|
||||
bundle exec pod install
|
||||
```
|
||||
|
||||
- Open the workspace in Xcode (`ios/authenticationsdk.xcworkspace`) and build to a device or simulator. For Face ID testing use a simulator with Face ID enabled or a device with Face ID configured.
|
||||
- The app uses `react-native-keychain` to prompt for biometrics / device passcode; no additional Xcode entitlements are required beyond the Info.plist usage string.
|
||||
|
||||
If biometrics are not available, the Keychain prompt can fall back to the device passcode when configured.
|
||||
|
||||
Testing notes:
|
||||
- Simulator: Device > Face ID > Enrolled to simulate Face ID responses.
|
||||
- Device: Make sure Face ID / Touch ID is configured in Settings.
|
||||
@@ -35,6 +35,8 @@
|
||||
</dict>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>This app uses Face ID to secure access to sensitive features.</string>
|
||||
<key>RCTNewArchEnabled</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
|
||||
@@ -1,16 +1,54 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { View, Text } from "react-native";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { View, Text, Alert } from "react-native";
|
||||
import { Camera, useCameraDevices } from "react-native-vision-camera";
|
||||
import { useFaceDetector } from "vision-camera-face-detector";
|
||||
import * as Keychain from "react-native-keychain";
|
||||
|
||||
export default function FaceRecognition() {
|
||||
const [authenticated, setAuthenticated] = useState(false);
|
||||
const devices = useCameraDevices();
|
||||
const device = devices.front;
|
||||
|
||||
useEffect(() => {
|
||||
Camera.requestCameraPermission();
|
||||
authenticateWithKeychain();
|
||||
}, []);
|
||||
|
||||
async function authenticateWithKeychain() {
|
||||
try {
|
||||
// Try to retrieve a protected generic password which will trigger
|
||||
// the system authentication prompt (Face ID / Touch ID / passcode).
|
||||
const creds = await Keychain.getGenericPassword({
|
||||
authenticationPrompt: { title: "Authenticate to unlock" },
|
||||
});
|
||||
|
||||
if (creds) {
|
||||
setAuthenticated(true);
|
||||
console.log("Authenticated via Keychain, credentials found.");
|
||||
return;
|
||||
}
|
||||
|
||||
// If no credentials stored yet, create one protected by biometrics
|
||||
await Keychain.setGenericPassword("user", "secure-token", {
|
||||
accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_ANY,
|
||||
accessible: Keychain.ACCESSIBLE.WHEN_PASSCODE_SET_THIS_DEVICE_ONLY,
|
||||
});
|
||||
|
||||
// Now request access which will prompt biometric/passcode
|
||||
const creds2 = await Keychain.getGenericPassword({
|
||||
authenticationPrompt: { title: "Authenticate to unlock" },
|
||||
});
|
||||
|
||||
if (creds2) {
|
||||
setAuthenticated(true);
|
||||
console.log("Authenticated after storing credentials.");
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.log("Authentication error:", e);
|
||||
Alert.alert("Authentication failed", e?.message || String(e));
|
||||
}
|
||||
}
|
||||
|
||||
const faceDetector = useFaceDetector({
|
||||
landmarkMode: "all",
|
||||
performanceMode: "fast",
|
||||
@@ -18,6 +56,13 @@ export default function FaceRecognition() {
|
||||
|
||||
if (!device) return <Text>Loading camera...</Text>;
|
||||
|
||||
if (!authenticated)
|
||||
return (
|
||||
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
|
||||
<Text>Locked. Please authenticate to continue.</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<Camera
|
||||
|
||||
Reference in New Issue
Block a user