UNPKG

@capgo/capacitor-native-biometric

Version:

This plugin gives access to the native biometric apis for android and iOS

550 lines (549 loc) 18.7 kB
import type { PluginListenerHandle } from '@capacitor/core'; export declare enum BiometryType { NONE = 0, TOUCH_ID = 1, FACE_ID = 2, FINGERPRINT = 3, FACE_AUTHENTICATION = 4, IRIS_AUTHENTICATION = 5, MULTIPLE = 6, DEVICE_CREDENTIAL = 7 } export declare enum AuthenticationStrength { /** * No authentication available, even if PIN is available but useFallback = false */ NONE = 0, /** * Strong authentication: Face ID on iOS, fingerprints on devices that consider fingerprints strong (Android). * Note: PIN/pattern/password is NEVER considered STRONG, even when useFallback = true. */ STRONG = 1, /** * Weak authentication: Face authentication on Android devices that consider face weak, * or PIN/pattern/password if useFallback = true (PIN is always WEAK, never STRONG). */ WEAK = 2 } export declare enum AccessControl { /** * No biometric protection. Credentials are accessible without authentication. * This is the default behavior for backward compatibility. */ NONE = 0, /** * Biometric authentication required for credential access. * Credentials are invalidated if biometrics change (e.g., new fingerprint enrolled). * More secure but credentials are lost if user modifies their biometric enrollment. */ BIOMETRY_CURRENT_SET = 1, /** * Biometric authentication required for credential access. * Credentials survive new biometric enrollment (e.g., adding a new fingerprint). * More lenient — recommended for most apps. */ BIOMETRY_ANY = 2 } export interface Credentials { username: string; password: string; } export interface IsAvailableOptions { /** * Whether passcode or device credentials should count toward biometric availability * when no biometric is enrolled or available. * * - On iOS, this affects both `isAvailable()` and `verifyIdentity()`. * - On Android, this is honored by `isAvailable()` only — the native check computes * `fallbackAvailable = useFallback && deviceIsSecure` and reports availability * accordingly. The `verifyIdentity()` flow ignores this option on Android due to * BiometricPrompt API constraints (DEVICE_CREDENTIAL authenticator and negative * button are mutually exclusive); use `BiometricOptions.useFallback` (iOS-only) to * control the auth-dialog fallback there. */ useFallback: boolean; } /** * Result from isAvailable() method indicating biometric authentication availability. */ export interface AvailableResult { /** * Whether authentication is available. * * On Android, weak-only biometrics (such as some face unlock implementations) * are available for `verifyIdentity()` when no `allowedBiometryTypes` filter * excludes them. If `useFallback` is true, PIN/pattern/password can also make * this value true. */ isAvailable: boolean; /** * The strength of available authentication method (STRONG, WEAK, or NONE) */ authenticationStrength: AuthenticationStrength; /** * The primary biometry type available on the device. * On Android devices with multiple biometry types, this returns MULTIPLE. * Use this for display purposes only - always use isAvailable for logic decisions. */ biometryType: BiometryType; /** * Whether the device has a secure lock screen (PIN, pattern, or password). * This is independent of biometric enrollment. */ deviceIsSecure: boolean; /** * Whether strong biometry (Face ID, Touch ID, or fingerprint on devices that consider it strong) * is specifically available, separate from weak biometry or device credentials. */ strongBiometryIsAvailable: boolean; /** * Error code from BiometricAuthError enum. Only present when isAvailable is false. * Indicates why biometric authentication is not available. * @see BiometricAuthError */ errorCode?: BiometricAuthError; } export interface BiometricOptions { reason?: string; title?: string; subtitle?: string; description?: string; negativeButtonText?: string; /** * Only for iOS. * Specifies if should fallback to passcode authentication if biometric authentication fails. * On Android, this parameter is ignored due to BiometricPrompt API constraints: * DEVICE_CREDENTIAL authenticator and negative button (cancel) are mutually exclusive. */ useFallback?: boolean; /** * Only for iOS. * Set the text for the fallback button in the authentication dialog. * If this property is not specified, the default text is set by the system. */ fallbackTitle?: string; /** * Only for Android. * Set a maximum number of attempts for biometric authentication. The maximum allowed by android is 5. * @default 1 */ maxAttempts?: number; /** * Only for Android. * Specify which biometry types are allowed for authentication. * If not specified, all enrolled biometric classes (strong and weak) are allowed. * On Android, face unlock is often classified as weak biometrics — include * `BiometryType.FACE_AUTHENTICATION` or omit this option to allow it. * Use `BiometryType.DEVICE_CREDENTIAL` for PIN/pattern/password (disables the cancel button). * @example [BiometryType.FINGERPRINT, BiometryType.FACE_AUTHENTICATION] */ allowedBiometryTypes?: BiometryType[]; } export interface GetCredentialOptions { server: string; } export interface SetCredentialOptions { username: string; password: string; server: string; /** * Access control level for the stored credentials. * When set to BIOMETRY_CURRENT_SET or BIOMETRY_ANY, the credentials are * hardware-protected and require biometric authentication to access. * * On iOS, this adds SecAccessControl to the Keychain item. * On Android, this creates a biometric-protected Keystore key and requires * BiometricPrompt authentication for both storing and retrieving credentials. * * @default AccessControl.NONE * @since 8.4.0 */ accessControl?: AccessControl; /** * Only for Android. Ignored on iOS and web. * Only meaningful together with `accessControl` set to BIOMETRY_CURRENT_SET or BIOMETRY_ANY. * * Number of seconds a successful biometric authentication remains valid for * Keystore key use. When `0` or omitted (the default), the Keystore key requires * a fresh authentication for every operation — each `getSecureCredentials()` call * shows a `BiometricPrompt` cryptographically bound to that specific read via a * `CryptoObject`. This is the strongest mode: it guarantees no code path can use * the key without a live biometric check. * * When set to a value greater than `0`, one successful biometric authentication * authorizes Keystore key use for that many seconds. Subsequent * `getSecureCredentials()` calls within the window succeed without showing a * prompt. This trades security for convenience: any in-app code that can reach * the decryption call — not just the code path that triggered the prompt — can * silently read the credentials for the remainder of the window. * * @default 0 * @since 8.5.0 */ authValidityDuration?: number; /** * Title for the biometric prompt shown while protecting credentials. * Only for Android. * * @default "Protect Credentials" * @since 8.4.14 */ title?: string; /** * Text for the negative/cancel button in the biometric prompt. * Only for Android. * * @default "Cancel" * @since 8.4.14 */ negativeButtonText?: string; } export interface GetSecureCredentialsOptions { server: string; /** * Reason for requesting biometric authentication. * Displayed in the biometric prompt on both iOS and Android. */ reason?: string; /** * Title for the biometric prompt. * Only for Android. */ title?: string; /** * Subtitle for the biometric prompt. * Only for Android. */ subtitle?: string; /** * Description for the biometric prompt. * Only for Android. */ description?: string; /** * Text for the negative/cancel button. * Only for Android. */ negativeButtonText?: string; } export interface DeleteCredentialOptions { server: string; } export interface IsCredentialsSavedOptions { server: string; } export interface IsCredentialsSavedResult { isSaved: boolean; } export interface SetDataOptions { /** * Unique identifier for the stored value. * Use a stable app-specific namespace (e.g. `pin`, `session.token`). */ key: string; /** * Arbitrary string payload. Serialize objects with `JSON.stringify()` before storing. * * Platform limits apply: Android Keystore-backed encryption works best with payloads * under ~8 KB; iOS Keychain practical limits are higher but very large values are discouraged. */ value: string; /** * Access control level for the stored value. * When set to BIOMETRY_CURRENT_SET or BIOMETRY_ANY, the value is hardware-protected * and requires biometric authentication to access via `getSecureData()`. * * @default AccessControl.NONE * @since 8.6.0 */ accessControl?: AccessControl; /** * Only for Android. Ignored on iOS and web. * Only meaningful together with `accessControl` set to BIOMETRY_CURRENT_SET or BIOMETRY_ANY. * * @default 0 * @since 8.6.0 */ authValidityDuration?: number; /** * Title for the biometric prompt shown while protecting data. * Only for Android. * * @default "Protect Data" * @since 8.6.0 */ title?: string; /** * Text for the negative/cancel button in the biometric prompt. * Only for Android. * * @default "Cancel" * @since 8.6.0 */ negativeButtonText?: string; } export interface GetDataOptions { key: string; } export interface GetSecureDataOptions { key: string; /** * Reason for requesting biometric authentication. * Displayed in the biometric prompt on both iOS and Android. */ reason?: string; /** * Title for the biometric prompt. * Only for Android. */ title?: string; /** * Subtitle for the biometric prompt. * Only for Android. */ subtitle?: string; /** * Description for the biometric prompt. * Only for Android. */ description?: string; /** * Text for the negative/cancel button. * Only for Android. */ negativeButtonText?: string; } export interface StoredData { value: string; } export interface DeleteDataOptions { key: string; } export interface IsDataSavedOptions { key: string; } export interface IsDataSavedResult { isSaved: boolean; } /** * Biometric authentication error codes. * These error codes are used in both isAvailable() and verifyIdentity() methods. * * Keep this in sync with BiometricAuthError in README.md * Update whenever `convertToPluginErrorCode` functions are modified */ export declare enum BiometricAuthError { /** * Unknown error occurred */ UNKNOWN_ERROR = 0, /** * Biometrics are unavailable (no hardware or hardware error) * Platform: Android, iOS */ BIOMETRICS_UNAVAILABLE = 1, /** * User has been locked out due to too many failed attempts * Platform: Android, iOS */ USER_LOCKOUT = 2, /** * No biometrics are enrolled on the device * Platform: Android, iOS */ BIOMETRICS_NOT_ENROLLED = 3, /** * User is temporarily locked out (Android: 30 second lockout) * Platform: Android */ USER_TEMPORARY_LOCKOUT = 4, /** * Authentication failed (user did not authenticate successfully) * Platform: Android, iOS */ AUTHENTICATION_FAILED = 10, /** * App canceled the authentication (iOS only) * Platform: iOS */ APP_CANCEL = 11, /** * Invalid context (iOS only) * Platform: iOS */ INVALID_CONTEXT = 12, /** * Authentication was not interactive (iOS only) * Platform: iOS */ NOT_INTERACTIVE = 13, /** * Passcode/PIN is not set on the device * Platform: Android, iOS */ PASSCODE_NOT_SET = 14, /** * System canceled the authentication (e.g., due to screen lock) * Platform: Android, iOS */ SYSTEM_CANCEL = 15, /** * User canceled the authentication * Platform: Android, iOS */ USER_CANCEL = 16, /** * User chose to use fallback authentication method * Platform: Android, iOS */ USER_FALLBACK = 17 } /** * Callback type for biometry change listener */ export type BiometryChangeListener = (result: AvailableResult) => void; export interface NativeBiometricPlugin { /** * Checks if biometric authentication hardware is available. * @param {IsAvailableOptions} [options] * @returns {Promise<AvailableResult>} * @memberof NativeBiometricPlugin * @since 1.0.0 */ isAvailable(options?: IsAvailableOptions): Promise<AvailableResult>; /** * Adds a listener that is called when the app resumes from background. * This is useful to detect if biometry availability has changed while * the app was in the background (e.g., user enrolled/unenrolled biometrics). * * @param eventName - Must be 'biometryChange' * @param {BiometryChangeListener} listener - Callback function that receives the updated AvailableResult * @returns {Promise<PluginListenerHandle>} Handle to remove the listener * @since 7.6.0 * * @example * ```typescript * const handle = await NativeBiometric.addListener('biometryChange', (result) => { * console.log('Biometry availability changed:', result.isAvailable); * }); * * // To remove the listener: * await handle.remove(); * ``` */ addListener(eventName: 'biometryChange', listener: BiometryChangeListener): Promise<PluginListenerHandle>; /** * Prompts the user to authenticate with biometrics. * @param {BiometricOptions} [options] * @returns {Promise<any>} * @memberof NativeBiometricPlugin * @since 1.0.0 */ verifyIdentity(options?: BiometricOptions): Promise<void>; /** * Gets the stored credentials for a given server. * @param {GetCredentialOptions} options * @returns {Promise<Credentials>} * @memberof NativeBiometricPlugin * @since 1.0.0 */ getCredentials(options: GetCredentialOptions): Promise<Credentials>; /** * Stores the given credentials for a given server. * @param {SetCredentialOptions} options * @returns {Promise<any>} * @memberof NativeBiometricPlugin * @since 1.0.0 */ setCredentials(options: SetCredentialOptions): Promise<void>; /** * Deletes the stored credentials for a given server. * @param {DeleteCredentialOptions} options * @returns {Promise<any>} * @memberof NativeBiometricPlugin * @since 1.0.0 */ deleteCredentials(options: DeleteCredentialOptions): Promise<void>; /** * Gets the stored credentials for a given server, requiring biometric authentication. * Credentials must have been stored with accessControl set to BIOMETRY_CURRENT_SET or BIOMETRY_ANY. * * On iOS, the system automatically shows the biometric prompt when accessing the protected Keychain item. * On Android, BiometricPrompt is shown with a CryptoObject bound to the credential decryption key. * * @param {GetSecureCredentialsOptions} options * @returns {Promise<Credentials>} * @memberof NativeBiometricPlugin * @since 8.4.0 */ getSecureCredentials(options: GetSecureCredentialsOptions): Promise<Credentials>; /** * Checks if credentials are already saved for a given server. * @param {IsCredentialsSavedOptions} options * @returns {Promise<IsCredentialsSavedResult>} * @memberof NativeBiometricPlugin * @since 7.3.0 */ isCredentialsSaved(options: IsCredentialsSavedOptions): Promise<IsCredentialsSavedResult>; /** * Stores an arbitrary string value under the given key. * Values are encrypted at rest using the platform secure storage backend * (Android Keystore + SharedPreferences, iOS Keychain). * * For biometric-protected storage, set `accessControl` and retrieve the value * with `getSecureData()`. Credential helpers remain available for username/password flows. * * @param {SetDataOptions} options * @returns {Promise<void>} * @memberof NativeBiometricPlugin * @since 8.6.0 */ setData(options: SetDataOptions): Promise<void>; /** * Gets a previously stored value for the given key. * Only returns values stored without biometric `accessControl`. * * @param {GetDataOptions} options * @returns {Promise<StoredData>} * @memberof NativeBiometricPlugin * @since 8.6.0 */ getData(options: GetDataOptions): Promise<StoredData>; /** * Gets a biometric-protected value for the given key. * The value must have been stored with `accessControl` set to BIOMETRY_CURRENT_SET or BIOMETRY_ANY. * * @param {GetSecureDataOptions} options * @returns {Promise<StoredData>} * @memberof NativeBiometricPlugin * @since 8.6.0 */ getSecureData(options: GetSecureDataOptions): Promise<StoredData>; /** * Deletes the stored value for the given key (protected and unprotected). * * @param {DeleteDataOptions} options * @returns {Promise<void>} * @memberof NativeBiometricPlugin * @since 8.6.0 */ deleteData(options: DeleteDataOptions): Promise<void>; /** * Checks whether a value is already saved for the given key. * * @param {IsDataSavedOptions} options * @returns {Promise<IsDataSavedResult>} * @memberof NativeBiometricPlugin * @since 8.6.0 */ isDataSaved(options: IsDataSavedOptions): Promise<IsDataSavedResult>; /** * Get the native Capacitor plugin version. * * @returns Promise that resolves with the plugin version * @since 1.0.0 */ getPluginVersion(): Promise<{ version: string; }>; }