Capacitor Biometric Authentication โ a project by Ahsan Mahmood
Framework-agnostic, provider-less biometric authentication library: one TypeScript API for WebAuthn + native biometric sign-in across Web, iOS, Android,โฆ
A fingerprint check on a phone proves something to that phone.
It proves nothing whatever to your server, and the distance between those two sentences is where most biometric login work quietly goes wrong. A screen decides the user is authenticated. The backend, which saw none of it, is then asked to agree on the strength of a message from the browser.
That gap is the shape this package is built around.
Before it, one feature meant three integrations. Android's BiometricPrompt has its own lifecycle. The browser has WebAuthn, which is a specification rather than a convenience API. Electron has its own arrangement again. Every application rebuilt all of it, in a different framework, usually under time pressure.
This makes it one call.
There is no provider to mount and no context to thread through a component tree. The same import works from React, Vue, Angular or plain JavaScript, and on a Capacitor build it becomes a native plugin without the calling code changing shape. On a pure web project the Capacitor core stays an optional peer, so a browser-only application carries none of the native surface.
The convenience is not the interesting part.
What the library returns is. A successful ceremony hands back a standard, server-verifiable WebAuthn response rather than a boolean saying yes.
A boolean is something the client says about itself.
A WebAuthn response is evidence a server can check against a credential it stored and a challenge it issued, which is a different kind of claim entirely, and it is the only kind worth putting behind a login.
That distinction is why the package declines to look simpler than it is.
Key material sits in hardware-backed storage wherever the platform provides it, so the private half never travels and never lands in a variable that some error tracker will helpfully serialise on the way to a dashboard.
Then there is the half almost nobody ships.
Verification belongs on a server. A client library that stopped at the browser would be an unfinished feature with a confident README, so a second package exists: webauthn-server-buildkit, which handles the relying-party side. Two packages, one author. That is the only reason the response one produces is the response the other expects.
The cost was holding two codebases in agreement instead of shipping one quickly. 71 tests on this side and 311 on the server side, plus four build outputs so it drops into a bundler that already has opinions.
There is a cost you inherit as well, and it is not a small one.
A biometric credential is bound to a device. A user who loses that device has lost that credential, so a recovery path is your product's job, and this library does not pretend to offer one. Anybody who tells you a biometric library solved account recovery has not read what it returns.
The native half is Android. There is no iOS release behind this work, because there is no Apple Developer account here.
MIT, on npm as capacitor-biometric-authentication, which is the one link this project has.
Read what it gives back before deciding it saves you time. If a boolean would have satisfied your product then the library was never the thing you were missing, and the honest saving here is measured in what your server can prove rather than in lines of code.
What it does, and what that costs to build
- One API for WebAuthn + native biometrics
- Framework-agnostic (React/Vue/Angular/vanilla JS)
- Provider-less Zustand-style state layer
- Capacitor-optional (zero footprint on pure web)
- Server-verifiable WebAuthn response
- Paired webauthn-server-buildkit server package
- Hardware-backed secure storage
Built with
- TypeScript
- CapacitorJS
- WebAuthn
- Swift
- Kotlin
- Rollup
Worth knowing
- npm
- package
- biometric
- webauthn
- authentication
- capacitor
Who built Capacitor Biometric Authentication?
Ahsan Mahmood built both halves of it: this client library and the server package it pairs with. That pairing is the point rather than a coincidence, because the response the client produces is exactly the response the server verifier expects, and the same person wrote both contracts. It is published on npm as capacitor-biometric-authentication under MIT, and the npm page is the single public link this project has. There is no company behind it and no support desk; one maintainer is the whole picture, stated here rather than discovered later.
Does a successful biometric check prove anything to my server?
Not on its own, and that gap is what this library is built around. A biometric check satisfies the device it happened on. Your backend has seen none of it and has no reason to agree. So a successful ceremony here returns a standard WebAuthn response your server can verify against a challenge it issued and a credential it stored, instead of a boolean the client simply asserts. Verifying that response is a separate job on a separate machine, which is what the companion webauthn-server-buildkit package exists to do.
Does Capacitor Biometric Authentication work on iPhone?
The WebAuthn path is a browser API, so it does whatever the browser on that device already supports, and none of that is code I wrote or can vouch for on Apple hardware. The native half is Android, through BiometricPrompt. There is no iOS release behind this work, because there is no Apple Developer account here and nothing I build has shipped to the App Store. Read anything Apple-shaped inside the package as unexercised rather than proven, which is the honest state of it.
Do I need Capacitor to use it?
No. The Capacitor core is an optional peer, so a browser-only project installs the package, gets the WebAuthn path, and carries none of the native surface in its bundle. Adding Capacitor later does not change your calling code, because the same API becomes a native plugin on a mobile build. That second direction matters more than it sounds. A team that ships a web application first and wraps it for mobile in year two does not rewrite its authentication layer to do it.
Where does the private key material live?
In hardware-backed secure storage wherever the platform offers it, which means the private half of a credential never travels and never lands in a JavaScript variable. That is a property of the device rather than something this library invented, and saying so plainly matters. A package cannot make a phone secure; it can only avoid undoing what the phone already does. What the library owns is the discipline around that: not copying the material, not logging it, and not exposing it through an API that would let your own error tracker serialise it by accident.
https://aoneahsan.com/projects/com.aoneahsan.capacitorbiometricauth