Using Biometric
Check for usable biometric hardware, then prompt the user with Face ID, Touch ID or the Android BiometricPrompt — all from one cross-platform API.
The whole module is one frozen namespace, Biometric, with three methods. Import it once:
import { Biometric } from '@sigx/lynx-biometric';
Basic usage
Always gate on isAvailable() before you prompt — it tells you whether the device has enrolled biometric hardware and never shows UI. Then call authenticate() with a reason. The prompt resolves to a result object you branch on.
import { Biometric } from '@sigx/lynx-biometric';
async function unlock() {
const { available, type } = await Biometric.isAvailable();
if (!available) {
// No enrolled biometrics — fall back to your own login flow.
return false;
}
const result = await Biometric.authenticate({
reason: 'Unlock your account',
});
return result.success;
}
type tells you which modality is enrolled ('faceId', 'touchId', 'fingerprint', 'face', 'iris' or 'none') so you can tailor copy or icons — for example showing a Face ID glyph on iPhone and a fingerprint glyph on most Android devices.
Handling the result
authenticate() ALWAYS resolves and never rejects. Every failure — including the user cancelling — comes back as success: false with a human-readable error and a machine-readable errorCode. You never need a try/catch around it.
import { Biometric } from '@sigx/lynx-biometric';
import type { BiometricErrorCode } from '@sigx/lynx-biometric';
async function unlock() {
const result = await Biometric.authenticate({
reason: 'Unlock your vault',
});
if (result.success) {
openVault();
return;
}
switch (result.errorCode as BiometricErrorCode) {
case 'userCancel':
// User dismissed the prompt — stay on the lock screen, no error toast.
break;
case 'biometryLockout':
// Too many failed attempts — ask for the device passcode instead.
showPasscodeFallback();
break;
case 'biometryNotEnrolled':
case 'biometryNotAvailable':
showPasswordLogin();
break;
default:
showError(result.error ?? 'Authentication failed');
}
}
Note on Android: a single fingerprint/face mismatch does NOT end the prompt — the OS keeps it up so the user can retry, so you will not see 'authenticationFailed' there. Only terminal outcomes (cancel, lockout, etc.) are reported. 'authenticationFailed' and 'userFallback' are iOS-only; 'noActivity' is Android-only.
Allowing the device passcode as a fallback
Set allowDeviceCredential: true to let the user fall back to the device PIN, passcode or pattern when biometrics fail or aren't enrolled. The platform-specific options let you customise the labels: title is the Android prompt title, fallbackTitle is the iOS fallback-button label.
import { Biometric } from '@sigx/lynx-biometric';
async function unlock() {
const result = await Biometric.authenticate({
reason: 'Unlock your account',
title: 'Acme Bank', // Android only — the BiometricPrompt title
fallbackTitle: 'Use Passcode', // iOS only — the fallback button text
allowDeviceCredential: true, // both platforms
});
if (result.success) proceed();
}
Security note: allowDeviceCredential: true degrades the gate to passcode strength — anyone who knows the device PIN can pass it. Leave it off for high-value actions where you want biometrics only.
Detecting an unwired build
If the native module wasn't linked into the build, the methods degrade gracefully instead of throwing. isAvailable() resolves to { available: false, type: 'none' } (without touching the bridge) and authenticate() resolves to { success: false, errorCode: 'biometryNotAvailable' }. You can also check explicitly:
import { Biometric } from '@sigx/lynx-biometric';
if (!Biometric.isModuleAvailable()) {
// Native module not in this build — hide the "Sign in with biometrics" button.
}
Native setup
sigx prebuild discovers the package and wires the native module automatically: it links the module, adds the iOS NSFaceIDUsageDescription and, on Android, the androidx.biometric dependency plus the normal-protection USE_BIOMETRIC permission (auto-granted at install on API 28+, no runtime prompt).
Apple rejects generic Face ID usage strings, so override the default in signalx.config.ts:
ios: {
usageDescriptions: {
NSFaceIDUsageDescription: 'Acme Bank uses Face ID to unlock your account.',
},
}
See Installation for the full setup walkthrough.
Notes
authenticate()never rejects — branch onresult.success, no try/catch needed.- A
reasonis required; passing an empty one resolves to a failure (errorCode: 'unknown') without prompting. - On iOS, biometrics enter lockout after 5 failed attempts and require the device passcode to reset.
- The iOS simulator ships with biometrics disabled — enrol via Features → Face ID → Enrolled before testing.
- Optic ID on Vision Pro (iOS 17+) is reported as
'iris'for cross-platform symmetry; the flow is otherwise unchanged.
See also
- Biometric API reference — every export and error code.
- Secure Storage — pair with Biometric to encrypt the unlocked credential at rest.
