@symbiote-native/local-auth wraps
expo-local-authentication
— hasHardwareAsync, isEnrolledAsync, getEnrolledLevelAsync,
supportedAuthenticationTypesAsync, authenticateAsync, cancelAuthenticate — so every
SymbioteNative adapter can drive it. Like sensors, it’s built on
expo-modules-core; but unlike sensors’ EventEmitter + live-subscription surface, every
function here is a one-shot async call with no per-instance state — the same imperative shape as
splash screen’s hide()/isVisible(). What sets it apart from
both: authenticateAsync resolves a discriminated ILocalAuthenticationResult success/error
union rather than a plain boolean, and several ILocalAuthenticationOptions fields only apply on
one platform (promptSubtitle, biometricsSecurityLevel — Android only; fallbackLabel — iOS
only) — worth knowing before you reach for one.
expo-local-authentication and expo-modules-core come along as regular dependencies, pinned to
exact versions — never install either yourself, and never add the expo meta-package to your
project (it bundles its own Metro/Babel pipeline, which conflicts with this project’s own).
All four adapters — React, Vue, Angular, Svelte — re-export the exact same free functions; there
is no per-adapter hook/composable/service to reach for, since nothing here holds live state or a
subscription. Probe capabilities once on mount, then call authenticateAsync from a button press
and branch on result.success.
authenticateAsync({ promptMessage: 'Confirm it is you' }).then(value=>this.result.set(value));
}
}
There’s no per-instance service to inject() here — every function is a plain free function
off the core package, called straight from the constructor, same as the real
examples/expo-angularLocalAuthScreen.
Determine what kinds of authentication are available on the device — a device can support several ([FINGERPRINT, FACIAL_RECOGNITION]), and an empty array means none
isEnrolledAsync(): Promise<boolean>
Determine whether the device has saved fingerprints or facial data to use for authentication
getEnrolledLevelAsync(): Promise<SecurityLevel>
Determine what kind of authentication is enrolled on the device — on pre-M Android devices this can read SECRET if only the SIM lock is enrolled, which authenticateAsync doesn’t actually prompt
Attempts to authenticate via Fingerprint/TouchID, or FaceID where available. symbiote-expo-link puts a default NSFaceIDUsageDescription into Info.plist; if that key is missing, iOS falls back to the device passcode instead of throwing
cancelAuthenticate(): Promise<void>
Cancels an in-flight authentication flow. @platform android
Authentication failed or couldn’t run; error is the machine-readable reason (see below), warning is an optional free-text detail some Android failures attach (e.g. KeyguardManager#isDeviceSecure() returned false)
Non-biometric authentication enrolled (PIN, pattern, or password)
BIOMETRIC_WEAK
2
Weak biometric authentication enrolled — e.g. 2D image-based face unlock; there are currently no weak options on iOS
BIOMETRIC_STRONG
3
Strong biometric authentication enrolled — e.g. a fingerprint scan or 3D face unlock
BIOMETRIC(deprecated)
aliases BIOMETRIC_STRONG/BIOMETRIC_WEAK
A getter kept for upstream compatibility that resolves to the platform-correct strong/weak member and logs a deprecation warning on every read — use BIOMETRIC_WEAK/BIOMETRIC_STRONG directly instead
@symbiote-native/local-auth ships zero React/Vue/Angular logic in expo-local-authentication
itself — that package’s own types file hard-imports Platform from the expo meta-package
(which this project never installs), so its functions, enums, and result types are hand-ported,
verbatim, into this package’s own core/, changing only that one import line to pull Platform
from expo-modules-core instead:
packages/local-auth/src/
├── core/ # framework-agnostic: the six exported functions, AuthenticationType,
│ # SecurityLevel, and the option/result/error types; native-module.ts resolves
│ # the native module via expo-modules-core's requireNativeModule
├── react/ # @symbiote-native/local-auth/react — export * from '../core'
├── vue/ # @symbiote-native/local-auth/vue — export * from '../core'
├── svelte/ # @symbiote-native/local-auth/svelte — export * from '../core'
└── angular/ # @symbiote-native/local-auth/angular — export * from '../core'
Unlike sensors’ react/hooks, vue/composables, svelte/runes, and angular/services folders
— each full of per-sensor lifecycle wrappers — local-auth’s four adapter entries are single-file
re-exports with no lifecycle code at all: every function here is stateless and one-shot, so there
is nothing for a hook, composable, rune, or service to subscribe to or clean up. The native code
itself is never
vendored or copied — expo-modules-autolinking resolves it straight out of node_modules (see
the native setup guide).