npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

capacitor-biometric-authentication

v2.3.3

Published

Biometric and WebAuthn authentication for web, iOS and Android — one API, no providers.

Downloads

1,049

Readme

npm version downloads license types bundle size node

Docs · npm · AI Guide · Support

[!IMPORTANT] A successful ceremony is not proof of identity on its own. On web, send result.webAuthnResponse to your server and verify it against the challenge your server issued. On iOS and Android the assertion does not reach your server at all in this version — treat native success as a local unlock, never as the basis for issuing a session. See Limitations.

One call — BiometricAuth.authenticate() — runs whatever ceremony the platform provides: WebAuthn in the browser, LocalAuthentication and the Secure Enclave on iOS, BiometricPrompt and the Android Keystore on Android, Touch ID or Windows Hello under Electron. There is no provider to mount and no React context to wire, so the same import works in React, Vue, Angular or plain JavaScript. Capacitor is an optional peer: install it for native, omit it and the web path still works.

| | | |---|---| | Version | 2.3.3 | | License | MIT | | Node | >=18.0.0 | | Platforms | Web · iOS · Android · Electron (macOS/Windows) | | Install size | ≈13 kB min+gzip (dist/web.js, measured) | | Types | Bundled .d.ts · ESM + CJS entry points | | Status | Stable · actively maintained |

🧭 Table of Contents #

💡 Why capacitor-biometric-authentication #

Biometric sign-in usually means writing the same flow three times: WebAuthn for the browser, a Capacitor plugin call for native, and a third path for desktop — each with its own option shape, its own error vocabulary, and its own idea of what "failed" means. This package collapses that into one method with one result type, and picks the adapter from the detected platform at runtime.

| | capacitor-biometric-authentication | A native-only biometric plugin | |---|---|---| | Web support | WebAuthn, server-verifiable | none — native only | | Capacitor required | optional peer | required | | Framework binding | none — direct calls | none, but usually paired with a wrapper | | Failure model | resolves with result.error | typically throws | | Server verification | web today; native planned for 2.4.0 | not provided |

Not the right tool when you need a server-verified assertion from iOS or Android — that path is not wired in this version, and no amount of client code works around it. It is also not the right tool for Cordova, React Native, or Electron on Linux, none of which have an adapter. If your app is native-only and you need a hardware-backed assertion reaching your backend, wait for 2.4.0 or use a native SDK directly.

✨ Features #

  • One API across four platforms — the adapter is chosen at runtime from the detected platform.
  • Provider-less — a direct import and direct calls; no context, no HOC, no plugin registration.
  • Server-verifiable on webauthenticate() hands back the standard WebAuthn JSON for your relying party to check.
  • Hardware-backed where the platform allows — Android Keystore, iOS Secure Enclave and Keychain, platform authenticators on web.
  • Never throwsauthenticate() always resolves; you branch on result.success and a canonical error code instead of writing try/catch.
  • Capacitor optional — declared as an optional peer and reached through a guarded dynamic import, so a pure web app never loads it.
  • TypeScript first — every option, result and error code is typed, and .d.ts files ship with the package.
  • No runtime dependencies.
  • Subscribable session state — a client-side session with a configurable duration and a subscribe() callback for UI binding.

📱 Platform Support #

| Platform | Supported | Notes | |---|---|---| | Web | ✅ | WebAuthn. Chrome 67+, Firefox 60+, Safari 14+, Edge 79+. HTTPS or localhost required. Server-verifiable. | | iOS | ⚠️ | iOS 13+. Touch ID / Face ID via LocalAuthentication + Secure Enclave. Local unlock only — the assertion does not reach your server. | | Android | ⚠️ | API 23+. BiometricPrompt + Android Keystore. Local unlock only — the assertion does not reach your server. | | Electron (macOS) | ✅ | Touch ID through the WebAuthn path. | | Electron (Windows) | ✅ | Windows Hello through the WebAuthn path, Windows 10+. | | Electron (Linux) | ❌ | No platform authenticator; isAvailable() returns false. A USB security key may still work. | | Cordova | ❌ | Detected, but no adapter ships. Loading one throws. | | React Native | ❌ | Detected, no adapter, no supported path. |

Full matrix with capability flags: Platform support.

📋 Requirements #

| Requirement | Version | Why | |---|---|---| | Node | >=18.0.0 | install and build tooling only — the library itself runs in a browser or WebView | | @capacitor/core | ^8.0.1 | optional peer — needed only for iOS and Android; the host app owns it | | Android minSdkVersion | 23 | BiometricPrompt arrived in Android 6.0 | | Android compileSdkVersion | 35 | matches the Capacitor 8 toolchain | | Java | 17 | required by the Android Gradle plugin used here | | Xcode | 15+ | to build the iOS plugin | | iOS deployment target | 13.0 | the LocalAuthentication APIs the plugin calls | | Secure context (web) | HTTPS or localhost | WebAuthn refuses to run on an insecure origin |

📦 Installation #

yarn add capacitor-biometric-authentication

Web only? That is the whole installation — Capacitor is not required.

Targeting iOS or Android? Sync the native projects, or the plugin is never registered and every native call quietly falls back to the web adapter:

npx cap sync

Then add the platform prerequisites.

iOS — add the Face ID usage string to ios/App/App/Info.plist. Without it the app crashes the first time Face ID is used:

<key>NSFaceIDUsageDescription</key>
<string>We use Face ID to confirm it is you before unlocking your account.</string>

Android — confirm android/app/build.gradle meets the levels in Requirements. The plugin declares its own USE_BIOMETRIC permission, so nothing needs adding to your manifest:

android {
    compileSdkVersion 35
    defaultConfig {
        minSdkVersion 23
        targetSdkVersion 35
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
}

🚀 Quick Start #

import BiometricAuth from 'capacitor-biometric-authentication';

async function signIn(): Promise<boolean> {
  // 1. Can we offer the button at all?
  if (!(await BiometricAuth.isAvailable())) {
    return signInWithPassword(); // always keep a non-biometric path
  }

  // 2. Run the ceremony. This resolves — it never throws.
  const result = await BiometricAuth.authenticate({
    reason: 'Sign in to your account',
    title: 'Biometric sign-in',
    fallbackTitle: 'Use passcode',
  });

  // 3. Branch on the failure, not on an exception.
  if (!result.success) {
    return signInWithPassword();
  }

  // 4. On web the ceremony is only a claim until your server verifies it.
  if (result.webAuthnResponse) {
    return verifyOnServer(result.webAuthnResponse);
  }

  return true;
}

🛠️ Usage #

Choosing the button label

getSupportedBiometrics() resolves to an array of strings describing what the device has.

const types = await BiometricAuth.getSupportedBiometrics();

let label: string;
if (types.includes('faceId')) label = 'Sign in with Face ID';
else if (types.includes('touchId')) label = 'Sign in with Touch ID';
else if (types.includes('fingerprint')) label = 'Sign in with your fingerprint';
else label = 'Sign in with biometrics';

Compare against the string values. BiometryType is exported from the package root as a type only, so BiometryType.FACE_ID does not exist at runtime — see Types.

Handling failure

import BiometricAuth, {
  BiometricErrorCode,
} from 'capacitor-biometric-authentication';

const result = await BiometricAuth.authenticate({ reason: 'Sign in' });

if (!result.success) {
  switch (result.error?.code) {
    case BiometricErrorCode.USER_CANCELLED:
      break; // the user chose not to — show nothing
    case BiometricErrorCode.NOT_ENROLLED:
      showMessage('Set up a fingerprint or face in your device settings first.');
      break;
    case BiometricErrorCode.LOCKED_OUT:
      showMessage('Too many attempts. Unlock your device, then try again.');
      break;
    case BiometricErrorCode.INSECURE_CONTEXT:
      showMessage('Biometric sign-in needs a secure (HTTPS) connection.');
      break;
    default:
      offerPasswordSignIn();
  }
}

BiometricErrorCode is a runtime value export, so this switch works as written.

Verifying on your server (web)

const result = await BiometricAuth.authenticate({
  reason: 'Sign in',
  webAuthnOptions: {
    get: {
      challenge: serverChallenge, // issued by YOUR server, for THIS attempt
      userVerification: 'required',
    },
  },
});

if (result.success && result.webAuthnResponse) {
  // result.webAuthnCeremony is 'registration' or 'authentication' —
  // it tells the server which endpoint should verify this payload.
  await fetch('/webauthn/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ response: result.webAuthnResponse }),
  });
}

The matching server-side verifier is webauthn-server-buildkit.

Tracking session state

const unsubscribe = BiometricAuth.subscribe((state) => {
  setSignedIn(state.isAuthenticated);
});

// later
unsubscribe();

Clearing credentials

BiometricAuth.logout(); // end the local session; stored credentials survive
await BiometricAuth.deleteCredentials(); // remove credentials — next attempt re-registers
const registered = await BiometricAuth.hasCredentials();

⚙️ Configuration #

BiometricAuth.configure({ sessionDuration: 3600, debug: false });

configure() returns void — it is not async.

| Option | Type | Default | What it does | |---|---|---|---| | adapter | 'auto' \| 'web' \| 'capacitor' \| 'electron' \| string | 'auto' | Forces a platform adapter instead of detecting one | | sessionDuration | number | 3600 | Local session lifetime in seconds | | debug | boolean | false | Verbose logging; warnings and errors are always emitted | | customAdapters | Record<string, BiometricAuthAdapter> | — | Adapters registered at configure time | | encryptionKey | string | — | Key material for the platform's secure storage | | requireAuthenticationForEveryAccess | boolean | false | Re-prompts on every sensitive operation | | uiConfig | BiometricUIConfig | — | Colours and logo where the platform's prompt is customisable | | fallbackMethods | FallbackMethod[] | — | Which device-credential fallbacks are permitted |

Per-call options — reason, title, subtitle, fallbackTitle, cancelTitle, maxAttempts — plus the platform-scoped platform.web, platform.android and platform.ios blocks are documented at Options.

🔧 API Reference #

Every method below is a property of the default export, BiometricAuth.

| Export | Signature | Docs | |---|---|---| | configure | (config: Partial<BiometricAuthConfiguration>) => void | | | isAvailable | () => Promise<boolean> | | | getSupportedBiometrics | () => Promise<BiometryType[]> | | | authenticate | (options?: BiometricAuthOptions) => Promise<BiometricAuthResult> | | | deleteCredentials | () => Promise<void> | | | hasCredentials | () => Promise<boolean> | | | logout | () => void | | | getState | () => BiometricAuthState | | | isAuthenticated | () => boolean | | | subscribe | (cb: (state: BiometricAuthState) => void) => () => void | | | requireAuthentication | (cb: () => void \| Promise<void>, options?: BiometricAuthOptions) => Promise<void> | | | withAuthentication | <T>(cb: () => T \| Promise<T>, options?: BiometricAuthOptions) => Promise<T> | | | registerAdapter | (name: string, adapter: BiometricAuthAdapter) => void | | | BiometricErrorCode | enum — a runtime value, named export | |

BiometricAuthCore, PlatformDetector, WebAdapter and CapacitorAdapter are also named exports — see Advanced Features.

🧩 Types #

import type {
  BiometricAuthOptions,
  BiometricAuthResult,
  BiometricAuthConfiguration,
  BiometricAuthAdapter,
  BiometricAuthState,
  BiometryType,
  BiometricError,
} from 'capacitor-biometric-authentication';

interface BiometricAuthResult {
  success: boolean;
  token?: string;
  sessionId?: string;
  error?: BiometricError;
  biometryType?: BiometryType;
  platform?: string;
  webAuthnResponse?: WebAuthnResponseJSON; // web only — send this to your server
  webAuthnCeremony?: 'registration' | 'authentication';
}

[!WARNING] BiometryType is re-exported from the package root with export type, so it has no runtime value there. Writing BiometryType.FINGERPRINT fails to compile with TS1362: 'BiometryType' cannot be used as a value because it was exported using 'export type', and is undefined in plain JavaScript. Import it for annotations and compare against its string values: 'fingerprint', 'faceId', 'touchId', 'iris', 'faceAuthentication', 'multiple', 'passcode', 'pattern', 'pin', 'opticId', 'unknown'. BiometricErrorCode is unaffected — it is a real value export.

🎛️ Advanced Features #

  • Custom adapters — implement BiometricAuthAdapter and register it with registerAdapter() to reach a platform this package does not.
  • Android Keystore crypto — sign or encrypt with a biometric-gated key through androidOptions.cryptoType, returned as result.androidCryptoResult.
  • Session helpersrequireAuthentication() and withAuthentication() prompt only when the local session has lapsed.
  • Forced adapter selection — pin configure({ adapter: 'web' }) to reproduce one platform's behaviour while developing on another.

🚑 Recovery & Troubleshooting #

| Symptom | Cause | Fix | |---|---|---| | error.code === 'INSECURE_CONTEXT' on web | WebAuthn refuses a non-secure origin | Serve over HTTPS, or develop on localhost | | App crashes on the first Face ID prompt | NSFaceIDUsageDescription is missing | Add the key to Info.plist — see Installation | | A native build behaves like a web build | npx cap sync was not run, so the native plugin never registered | Run npx cap sync, then configure({ debug: true }) and read which adapter loaded | | Cordova support not yet implemented | No Cordova adapter ships | Use Capacitor for native | | TS1362: 'BiometryType' cannot be used as a value | BiometryType is a type-only export | Compare against its string values — see Types | | isAvailable() returns false on Electron/Linux | Linux exposes no platform authenticator | Offer a USB security key or a password path | | success: true but your server rejects the user | The client result is a claim, not proof | Verify webAuthnResponse server-side; the server wins |

🚧 Limitations #

  • Native ceremonies are not server-verifiable in 2.3.1. The Capacitor bridge does not forward webAuthnOptions to the native layer, and the native register() ceremony is not on the JavaScript surface — so an iOS or Android assertion never reaches your relying party. Treat native success as a local unlock. Planned for 2.4.0.
  • isAuthenticated() is a UX gate, not a security boundary — a client-side flag with a timer. It decides whether to prompt again, never whether to release data.
  • isAvailable() returns a plain boolean and does not say why something is unavailable.
  • You cannot require a specific modality. getSupportedBiometrics() is a hint for UI copy; the OS decides which enrolled modality satisfies the prompt.
  • No Cordova, React Native, or Electron-on-Linux adapter.
  • BiometryType has no runtime value at the package root — see Types.
  • No automated test suite ships. Quality is gated by typecheck, lint, a clean multi-format build, and verified ESM, CommonJS and subpath imports of the packed tarball.
  • On web only the credential id is stored locally. The private key never leaves the authenticator, which is correct — but it means this package cannot offer key export or backup.

❓ FAQ #

Do I need Capacitor? No. @capacitor/core is an optional peer, reached only through a guarded dynamic import on native. A pure web app never pulls it in.

Does authenticate() throw? No. It always resolves. Check result.success and result.error?.code.

Why is BiometryType.FACE_ID undefined? It is exported as a type only. Compare against the string 'faceId' — see Types.

Is success: true enough to sign a user in? Not on its own. On web, verify result.webAuthnResponse on your server. On native there is nothing to verify in this version — see Limitations.

Is sessionDuration in seconds or milliseconds? Seconds. The default is 3600.

Does it work from a plain <script> tag? Yes — the package ships an IIFE build for a classic script tag and an ES build for <script type="module">.

📚 Documentation #

| Document | Read it when | |---|---| | Introduction | deciding whether this package fits | | Installation | setting it up, including the native steps | | Quick start | building your first working flow | | API — methods | you need an exact signature | | API — options | tuning per-call or per-platform behaviour | | API — types | writing type annotations against the result | | API — error codes | mapping a failure to user-facing copy | | Security model | before you ship — what success: true proves | | Server verification | wiring the relying-party side | | Framework examples | using it from React, Vue, Angular or vanilla JavaScript | | Platform support | checking what a target really provides | | llms.txt | a coding agent is implementing against this package |

🔄 Changelog #

Latest release: 2.3.3 — documentation only: the at-a-glance table above reported the previous version, because it is a static duplicate of package.json. Full history in the changelog.

The full history ships inside the package at node_modules/capacitor-biometric-authentication/CHANGELOG.md.

🗺️ Roadmap #

  • 2.4.0 — server-verifiable native ceremonies: forward webAuthnOptions through the Capacitor bridge and expose the native register() ceremony, so an iOS or Android assertion can reach your relying party. This is the one gap that changes what the package can be used for.

🤝 Contributing #

The source repository is private, so there is no public fork-and-pull-request path today. Bug reports, reproductions and feature requests are welcome by email at [email protected]. A minimal reproduction plus the platform, package version, and browser or OS version makes a report immediately actionable.

💬 Support #

Questions and bug reports: [email protected].

If this package saves you time, you can support its maintenance at aoneahsan.com/payment.

📄 License #

MIT © Ahsan Mahmood. The full text ships in the package as LICENSE.

👤 Author #

Ahsan Mahmoodaoneahsan.com · GitHub · LinkedIn · [email protected]

🔗 Links #

| | | |---|---| | Documentation | https://capacitor-biometric-authentication-docs.aoneahsan.com | | npm | https://www.npmjs.com/package/capacitor-biometric-authentication | | AI agent guide | https://capacitor-biometric-authentication-docs.aoneahsan.com/llms.txt | | Server-side verifier | https://www.npmjs.com/package/webauthn-server-buildkit | | Support the project | https://aoneahsan.com/payment | | Author | https://aoneahsan.com |

🏷️ Keywords #

capacitor · capacitor-plugin · biometric · authentication · webauthn · passkey · fingerprint · face-id · touch-id · android · ios · framework-agnostic