capacitor-biometric-authentication
v2.3.1
Published
Framework-agnostic biometric authentication library. Works with React, Vue, Angular, or vanilla JS. No providers required!
Maintainers
Readme
Biometric Authentication
A framework-agnostic biometric authentication library for React, Vue, Angular, or vanilla JavaScript. No providers required!
Links
- Website & Documentation - Interactive demos, API reference, guides
- Playground - Try WebAuthn in your browser
- AI Integration Guide - Complete full-stack integration guide
- Backend Package - Server-side WebAuthn implementation
- Portfolio Info File -
CAPACITOR-BIOMETRIC-AUTHENTICATION_portfolio-info_2026-03-24.md
Current State
- Package version:
2.3.0 - Tests:
71/71passing via thetestscript in the last verification pass - Build: the
buildscript succeeds in the last verification pass - Runtime coverage in package architecture:
- WebAuthn via the web adapter, returning a server-verifiable
webAuthnResponse - Capacitor native support for iOS and Android
- Electron adapter included in source
- Shared core/state logic for framework-agnostic usage
- WebAuthn via the web adapter, returning a server-verifiable
Features
- Zero Dependencies - Works without any specific framework (Capacitor optional)
- Provider-less - Direct API like Zustand, no Context/Providers needed
- Multi-Platform - Web (WebAuthn), iOS, Android, Electron support
- Framework Agnostic - Works with React, Vue, Angular, Vanilla JS
- TypeScript First - Full type safety and IntelliSense
- Server-verifiable on web - Returns the standard WebAuthn JSON for relying-party verification
- Hardware-backed secure storage - Android Keystore, iOS Secure Enclave + Keychain, platform authenticators on web
- Tiny Bundle - Tree-shakeable with dynamic imports
- Backward Compatible - Works as a Capacitor plugin too
Security model: A successful authentication (
result.success === true) means the local biometric / WebAuthn ceremony completed. On its own it is not proof of identity. On web, sendresult.webAuthnResponseto your relying-party server (for examplewebauthn-server-buildkit) and verify it against the challenge the server issued.isAuthenticated()and the client session are a UX gate, not a security boundary. See Security Best Practices.
Installation
yarn add capacitor-biometric-authenticationPackage Manager Policy
- Use
yarnfor project-local installs and script execution. - Use
pnpmfor global package installs. - Use
npmonly to install or updatepnpmglobally. - Keep
yarn.lockand remove other lockfiles.
Quick Start
import BiometricAuth from 'capacitor-biometric-authentication';
// Check availability (resolves to a boolean)
const available = await BiometricAuth.isAvailable();
// Run the biometric / WebAuthn ceremony. authenticate() never throws —
// inspect result.success and result.error instead.
const result = await BiometricAuth.authenticate({
reason: 'Please authenticate to continue',
});
if (result.success) {
// On web, result.webAuthnResponse is the standard WebAuthn JSON.
// Send it to your server to VERIFY before trusting the user's identity.
console.log('Local ceremony completed', result.webAuthnCeremony);
} else {
console.log('Failed:', result.error?.code, result.error?.message);
}Verified Package Architecture
src/core/contains the shared biometric auth orchestration and platform detection logic.src/adapters/contains Web (WebAuthn), Capacitor, and Electron adapters.src/types/is the canonical type source, including thewebAuthnResponseshapes used for server verification.src/utils/contains session, encoding, and error utilities.android/andios/contain native plugin implementations.tests/currently covers encoding and error-handling utilities with Vitest (71 tests).
Verification Commands
yarn test
yarn buildProduction Integration Guide
This section provides step-by-step instructions for integrating this plugin into a production Capacitor app.
Prerequisites
- Node.js
>=18.0.0 - Capacitor 8.x (
@capacitor/core ^8.0.1peer dependency; optional — the web adapter works without Capacitor) - For iOS: Xcode 15+, CocoaPods
- For Android: Android Studio, JDK 17
Step 1: Install the Plugin
yarn add capacitor-biometric-authenticationStep 2: Sync Native Projects
npx cap syncStep 3: Platform-Specific Configuration
Android Configuration
Minimum Requirements:
minSdkVersion: 23 (Android 6.0)compileSdkVersion: 35- Java 17
The plugin automatically includes required permissions in its AndroidManifest.xml:
<uses-permission android:name="android.permission.USE_BIOMETRIC" />Verify Gradle Settings (android/app/build.gradle):
android {
compileSdkVersion 35
defaultConfig {
minSdkVersion 23
targetSdkVersion 35
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
}iOS Configuration
Minimum Requirements:
- iOS 13.0+
- Swift 5.1+
Required Info.plist Entry:
Add to ios/App/App/Info.plist:
<key>NSFaceIDUsageDescription</key>
<string>We use Face ID to securely authenticate you</string>Note: This key is required for Face ID devices. Without it, your app will crash when attempting Face ID authentication.
Web Configuration
Requirements:
- HTTPS (or localhost for development)
- Browser with WebAuthn support (Chrome 67+, Safari 14+, Firefox 60+, Edge 79+)
- Platform authenticator (TouchID, Windows Hello, etc.)
Development:
yarn dev # localhost works without HTTPSProduction: Ensure your site uses HTTPS. WebAuthn will not work on non-secure origins.
Step 4: Use the Plugin
import BiometricAuth from 'capacitor-biometric-authentication';
// Check if biometrics are available
const available = await BiometricAuth.isAvailable();
if (available) {
// Configure session duration (in seconds)
BiometricAuth.configure({
sessionDuration: 3600, // 1 hour
});
// Authenticate
const result = await BiometricAuth.authenticate({
reason: 'Authenticate to access your account',
fallbackTitle: 'Use Passcode',
});
if (result.success) {
console.log('Authenticated!');
} else {
console.error('Auth failed:', result.error?.message);
}
}Step 5: Build and Run
Web:
yarn build
yarn previewAndroid:
npx cap sync android
npx cap run android
# or open in Android Studio:
npx cap open androidiOS:
npx cap sync ios
cd ios && pod install && cd ..
npx cap run ios
# or open in Xcode:
npx cap open iosFramework Examples
React Example
import { useState, useEffect } from 'react';
import BiometricAuth from 'capacitor-biometric-authentication';
function SecureComponent() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
const unsubscribe = BiometricAuth.subscribe((state) => {
setIsAuthenticated(state.isAuthenticated);
});
return unsubscribe;
}, []);
const handleLogin = async () => {
const result = await BiometricAuth.authenticate({
reason: 'Access your account',
});
if (!result.success) console.error('Auth failed:', result.error);
};
return isAuthenticated ? (
<h1>Welcome back!</h1>
) : (
<button onClick={handleLogin}>Login with Biometrics</button>
);
}Vue Example
<template>
<button
v-if="!isAuthenticated"
@click="authenticate"
>
Login with Biometrics
</button>
<div v-else>Welcome back!</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import BiometricAuth from 'capacitor-biometric-authentication';
const isAuthenticated = ref(false);
let unsubscribe;
onMounted(() => {
unsubscribe = BiometricAuth.subscribe((state) => {
isAuthenticated.value = state.isAuthenticated;
});
});
onUnmounted(() => unsubscribe?.());
const authenticate = () =>
BiometricAuth.authenticate({ reason: 'Access your account' });
</script>Vanilla JavaScript
<script type="module">
import BiometricAuth from 'https://unpkg.com/capacitor-biometric-authentication/dist/web.js';
document.getElementById('auth-btn').addEventListener('click', async () => {
const result = await BiometricAuth.authenticate({
reason: 'Please authenticate',
});
if (result.success)
document.getElementById('status').textContent = 'Authenticated!';
});
</script>
<button id="auth-btn">Authenticate</button>
<div id="status"></div>API Reference
Core Methods
| Method | Returns | Description |
| -------------------------- | -------------------------------- | --------------------------------------------------------------- |
| configure(config) | void | Set plugin configuration (adapter, session duration, debug) |
| isAvailable() | Promise<boolean> | Check if biometric auth is available |
| getSupportedBiometrics() | Promise<BiometryType[]> | Get available biometric types |
| authenticate(options?) | Promise<BiometricAuthResult> | Run the ceremony; resolves with { success, error?, webAuthnResponse? } (never throws) |
| deleteCredentials() | Promise<void> | Clear stored credentials and end the session |
| hasCredentials() | Promise<boolean> | Whether a credential is stored on this device |
| logout() | void | Clear the local authentication session |
State Management
| Method | Returns | Description |
| --------------------- | ------------------------ | -------------------------------------------------------------------------- |
| subscribe(callback) | () => void | Subscribe to auth-state changes; returns an unsubscribe function |
| getState() | BiometricAuthState | Get a snapshot of the current local auth state |
| isAuthenticated() | boolean | Whether the local session is still valid — a UX gate, not a security boundary |
Utility Methods
| Method | Returns | Description |
| ------------------------------------------- | --------------------- | ------------------------------------------------------------ |
| requireAuthentication(callback, options?) | Promise<void> | Authenticate (if not already) then run callback |
| withAuthentication(callback, options?) | Promise<T> | Authenticate (if not already) then run callback and return its value |
| registerAdapter(name, adapter) | void | Register a custom platform adapter (advanced) |
Configuration Options
BiometricAuth.configure({
adapter: 'auto', // 'auto' | 'web' | 'capacitor' | 'electron' | custom name
sessionDuration: 3600, // Local session duration in SECONDS (default: 3600)
debug: false, // Enable debug logging
});configure() returns void (it is not async).
Authentication Options
await BiometricAuth.authenticate({
reason: 'Authentication Required', // Displayed to user
title: 'Biometric Login', // Android dialog title
subtitle: 'Log in to your account', // Android dialog subtitle
fallbackTitle: 'Use Passcode', // Fallback button text
cancelTitle: 'Cancel', // Cancel button text
disableDeviceCredential: false, // Disable passcode fallback
maxAttempts: 3, // Max failed attempts before lockout
// Web only: pass the server-issued challenge so the response can be verified.
platform: {
web: { challenge: serverChallenge, userVerification: 'required' },
},
});On web, userVerification defaults to 'required' and a secure context (HTTPS or localhost) is mandatory — otherwise authenticate() resolves with error.code === 'INSECURE_CONTEXT'. See the Web Platform Guide and WebAuthn Advanced for the full server-verified flow.
Platform Support
| Platform | Technology | Min Version | Status | | ------------------ | ------------------ | ----------- | ------ | | Web | WebAuthn API | Chrome 67+ | ✅ | | iOS | Touch ID / Face ID | iOS 13.0 | ✅ | | Android | BiometricPrompt | API 23 | ✅ | | Electron (macOS) | Touch ID | - | ✅ | | Electron (Windows) | Windows Hello | Windows 10 | ✅ |
Browser Support
- Chrome/Edge 67+ (Windows Hello, Touch ID)
- Safari 14+ (Touch ID, Face ID)
- Firefox 60+ (Windows Hello)
Windows Hello Support (Electron)
The plugin supports Windows Hello on Electron for Windows platforms. When running on Windows (win32), the ElectronAdapter automatically uses the WebAuthn API to interface with Windows Hello.
Requirements:
- Windows 10 or later
- Windows Hello configured in Windows Settings
- Electron with WebAuthn support
Usage: The same API works across all platforms:
// Works on macOS (Touch ID) and Windows (Windows Hello)
const result = await BiometricAuth.authenticate({
reason: 'Authenticate with Windows Hello',
});Error Handling
authenticate() resolves rather than throwing; branch on result.error?.code using the canonical BiometricErrorCode values.
import BiometricAuth, {
BiometricErrorCode,
} from 'capacitor-biometric-authentication';
const result = await BiometricAuth.authenticate();
if (!result.success) {
switch (result.error?.code) {
case BiometricErrorCode.USER_CANCELLED:
console.log('User cancelled');
break;
case BiometricErrorCode.AUTHENTICATION_FAILED:
console.log('Biometric not recognized');
break;
case BiometricErrorCode.NOT_AVAILABLE:
console.log('Biometric not available');
break;
case BiometricErrorCode.LOCKED_OUT:
console.log('Too many failed attempts');
break;
case BiometricErrorCode.NOT_ENROLLED:
console.log('No biometrics enrolled');
break;
case BiometricErrorCode.INSECURE_CONTEXT:
console.log('Web requires HTTPS or localhost');
break;
default:
console.log('Error:', result.error?.code, result.error?.message);
}
}The legacy aliases
BIOMETRIC_UNAVAILABLE,LOCKOUT, andUNKNOWN_ERRORare deprecated. Adapters now emit only canonical codes — useNOT_AVAILABLE,LOCKED_OUT, andUNKNOWN. See the Error Handling Overview for the full list.
Troubleshooting
For build failures and common integration issues, see the comprehensive Troubleshooting Guide.
Common issues covered:
- Android Gradle/SDK version mismatches
- iOS Info.plist missing entries
- Pod installation failures
- WebAuthn HTTPS requirements
- Plugin registration issues
Development
# Install dependencies
yarn install
# Build plugin
yarn build
# Watch mode
yarn watch
# Lint & format
yarn lint
yarn prettier
# Test in example app
cd example
yarn install
yarn dev # Web development
yarn cap:sync # Sync native platforms
yarn cap:ios:run # Run on iOS
yarn cap:android:run # Run on AndroidProject Structure
├── src/ # TypeScript source
│ ├── index.ts # Public API entry (default export: BiometricAuth)
│ ├── core/ # Orchestration + platform detection
│ ├── adapters/ # Web (WebAuthn), Capacitor, Electron adapters
│ ├── types/ # Canonical types (incl. webAuthnResponse shapes)
│ └── utils/ # Encoding, error, logger utilities
├── android/ # Android native (BiometricPrompt + Keystore)
├── ios/ # iOS native (LocalAuthentication + Secure Enclave/Keychain)
├── example/ # React example app
└── docs/ # DocumentationPlugin Metadata
| Property | Value |
| ----------------- | --------------------------------------- |
| Package Name | capacitor-biometric-authentication |
| Plugin ID | BiometricAuth |
| Android Package | com.aoneahsan.capacitor.biometricauth |
| iOS Class | BiometricAuthPlugin |
| Capacitor Version | 8.x |
Documentation
Full documentation in docs/:
- Installation Guide
- Quick Start
- Platform Guides - iOS, Android, Web
- API Reference
- FAQ
Contributing
See Contributing Guide for details.
Support
Changelog
See CHANGELOG.md for release history.
License
MIT © Ahsan Mahmood
