From e5bb867723e7d66d38cea37ff0b6e4fc9807a1d5 Mon Sep 17 00:00:00 2001 From: mansi-dev Date: Sat, 24 Jan 2026 23:23:42 +0530 Subject: [PATCH] Implement Face ID authentication and update iOS configuration for biometric support --- docs/IOS_BIOMETRICS.md | 21 ++++++++++++++ ios/authenticationsdk/Info.plist | 2 ++ src/screen/FaceAuth.tsx | 49 ++++++++++++++++++++++++++++++-- 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 docs/IOS_BIOMETRICS.md diff --git a/docs/IOS_BIOMETRICS.md b/docs/IOS_BIOMETRICS.md new file mode 100644 index 0000000..29f6641 --- /dev/null +++ b/docs/IOS_BIOMETRICS.md @@ -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. diff --git a/ios/authenticationsdk/Info.plist b/ios/authenticationsdk/Info.plist index f9ea6a5..9f1cc36 100644 --- a/ios/authenticationsdk/Info.plist +++ b/ios/authenticationsdk/Info.plist @@ -35,6 +35,8 @@ NSLocationWhenInUseUsageDescription + NSFaceIDUsageDescription + This app uses Face ID to secure access to sensitive features. RCTNewArchEnabled UILaunchStoryboardName diff --git a/src/screen/FaceAuth.tsx b/src/screen/FaceAuth.tsx index c96d162..566fc6f 100644 --- a/src/screen/FaceAuth.tsx +++ b/src/screen/FaceAuth.tsx @@ -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 Loading camera...; + if (!authenticated) + return ( + + Locked. Please authenticate to continue. + + ); + return (