Biometrics
Add Face ID and fingerprint authentication to your mobile app with expo-local-authentication.
Biometrics
ScaleRocket Mobile includes expo-local-authentication for biometric authentication — Face ID on iPhone, fingerprint on Android, and Touch ID on older Apple devices.
Check Availability
Before prompting for biometrics, check if the device supports it and if the user has enrolled:
import * as LocalAuthentication from "expo-local-authentication";
async function checkBiometrics() {
// Check if hardware supports biometrics
const compatible = await LocalAuthentication.hasHardwareAsync();
if (!compatible) return false;
// Check if user has enrolled biometrics (face/fingerprint registered)
const enrolled = await LocalAuthentication.isEnrolledAsync();
if (!enrolled) return false;
return true;
}You can also check which types of biometrics are available:
const types = await LocalAuthentication.supportedAuthenticationTypesAsync();
// Returns: [1] for fingerprint, [2] for facial recognition, or bothAuthenticate the User
Prompt the user for biometric authentication:
async function authenticateWithBiometrics() {
const result = await LocalAuthentication.authenticateAsync({
promptMessage: "Authenticate to continue",
fallbackLabel: "Use passcode",
cancelLabel: "Cancel",
disableDeviceFallback: false, // Allow passcode as fallback
});
if (result.success) {
// User authenticated successfully
return true;
} else {
// Authentication failed or was cancelled
console.log(result.error);
return false;
}
}Re-Authentication Flow
Use biometrics as a secondary gate after session check. For example, require biometrics when the app returns from background:
import { useEffect, useRef } from "react";
import { AppState } from "react-native";
function useBiometricLock() {
const appState = useRef(AppState.currentState);
const [isLocked, setIsLocked] = useState(false);
useEffect(() => {
const subscription = AppState.addEventListener("change", (nextState) => {
if (
appState.current.match(/inactive|background/) &&
nextState === "active"
) {
setIsLocked(true);
authenticateWithBiometrics().then((success) => {
if (success) setIsLocked(false);
});
}
appState.current = nextState;
});
return () => subscription.remove();
}, []);
return isLocked;
}Use Cases
| Scenario | Implementation |
|---|---|
| App lock | Re-authenticate when app returns from background |
| Sensitive actions | Require biometrics before deleting account or changing password |
| Quick login | Offer biometric login instead of typing credentials |
| Payment confirmation | Verify identity before processing payments |
Important Notes
- Biometrics require a development build (not Expo Go)
- iOS simulators support simulated Face ID (Features > Face ID in the simulator menu)
- Android emulators support simulated fingerprint (Extended controls > Fingerprint)
- Always provide a fallback (passcode) for accessibility
- On iOS, add
NSFaceIDUsageDescriptiontoapp.jsonunderios.infoPlist:
{
"expo": {
"ios": {
"infoPlist": {
"NSFaceIDUsageDescription": "We use Face ID to secure your account"
}
}
}
}