Skip to content
Shiny.NET
Commercial SupportGuaranteed response times on Shiny bug fixes, straight from the maintainers. Plans from US$1,500 a year.See the plans

Biometrics

NuGet package Shiny.AppDeviceBridge.Biometrics

The biometrics bridge shows the platform’s own biometric prompt to the page, for example to unlock a vault or confirm a sensitive action. It’s built on Shiny.Biometrics.

Platform Backed by
iOS, Mac Catalyst, macOS LocalAuthentication: Touch ID, Face ID, Optic ID. On macOS a paired Apple Watch also works when the passcode is allowed
Android AndroidX BiometricPrompt: fingerprint, face, iris
Windows Windows Hello: face, fingerprint or the Hello PIN
Linux nothing: every route answers 501

A device without biometric hardware still answers, with status: "NotSupported".

Terminal window
dotnet add package Shiny.AppDeviceBridge.Biometrics
builder.UseAppDeviceBridge(
bridge => bridge.AddBiometricsBridge(),
webApp => { /* … */ }
);

On iOS, add NSFaceIDUsageDescription to Info.plist. Without it, prompting on a Face ID device answers 409 cannot_prompt. Android and Windows need nothing. See Shiny.Biometrics.

import { BiometricsBridge } from "@shinyorg/appdevicebridge";
const biometrics = new BiometricsBridge();
const availability = await biometrics.getAvailability();
if (availability.status === "Available" || availability.isDeviceCredentialSet) {
const result = await biometrics.authenticate({
reason: "Unlock your vault",
allowDeviceCredential: true
});
if (result.status === "Success")
unlockVault();
else if (result.status === "Fallback")
showPasswordLogin();
}

In Blazor, register AddBiometricsBridgeClient() and inject IBiometricsBridge.

GET biometrics reports, with no UI:

Field Meaning
status Available, NotSupported (no hardware), NotEnrolled, LockedOut (the passcode unlocks it), PasscodeNotSet (Apple), Unavailable (busy, disconnected or disabled by policy), SecurityUpdateRequired (Android)
types The hardware present, even when nothing is enrolled: Fingerprint, Face, Iris, or Unknown for Windows Hello. Apple reports one, Android every sensor the device declares
isDeviceCredentialSet A passcode, PIN or pattern is set, so allowDeviceCredential has something to fall back to

Use types to label the button: “Face ID”, “Touch ID”, “Fingerprint” or “Windows Hello”. ?strength=Weak asks Android about class 2 biometrics, which includes most camera-based face unlock.

POST biometrics/authenticate shows the prompt and answers { status, errorMessage }. A cancel, lockout or missing enrollment is a status, not an error:

status Meaning
Success The device owner was verified
Cancelled The user or the system dismissed the prompt
Fallback Apple: the user tapped the fallback button. Show your own login
Failed, LockedOut, NotEnrolled, PasscodeNotSet, NotAvailable, Timeout Show errorMessage, the platform’s own message
Field Platforms Meaning
reason All Required, at most 256 characters. Shown in the prompt
title, subtitle Android The prompt’s title (defaults to reason) and a line under it
cancelText Apple, Android The cancel button
fallbackText Apple The button after a failed match. null keeps “Enter Password”, "" hides it
allowDeviceCredential All Accept the passcode, PIN or pattern too. Windows Hello always offers its PIN
strength Android Strong (class 3, the default) or Weak (class 2)
confirmationRequired Android For face, wait for the user to confirm after a match. On by default

Aborting the request (an AbortSignal, or a cancelled token in C#) dismisses the prompt.

Status Code When
400 bad_request The reason is empty, or a text is over 256 characters
409 cannot_prompt The app has nothing to show the prompt from: no Android activity, or a missing NSFaceIDUsageDescription
501 not_supported Linux, or the app did not register the bridge
GET/_bridge/biometrics#

What the device can do right now (hardware, enrollment, lockout, passcode), with no UI. On Android, strength is the class of biometric the page will ask for.

C#IBiometricsBridge.GetAvailabilityAsyncTSBiometricsBridge.getAvailability
ParameterInType
strengthqueryBiometricStrengthoptional
Response
200 BiometricAvailability
BiometricAvailability · 3 fields
statusBiometricStatusWhether biometrics can be used right now.
typesBiometricType[]The hardware present, reported even when nothing is enrolled or biometrics are locked out. Apple reports one type, Android every sensor the device declares, and Windows Unknown.
isDeviceCredentialSetbooleanA passcode, PIN or pattern is set, so allowDeviceCredential has something to fall back to.
POST/_bridge/biometrics/authenticate#

Shows the platform prompt. A cancel, lockout or missing enrollment is a result (status), not an error. Fails with 400 when the reason is empty or longer than 256 characters, and with 409 cannot_prompt when the app has nothing to show the prompt from (no Android activity, or an iOS app missing NSFaceIDUsageDescription).

C#IBiometricsBridge.AuthenticateAsyncTSBiometricsBridge.authenticate
Body
application/json · BiometricRequest
BiometricRequest · 8 fields
reasonstringWhy the page is asking; shown in the prompt on every platform. Required, at most 256 characters.
titlestring | nullAndroid: the prompt title (defaults to reason).
subtitlestring | nullAndroid: a line under the title.
cancelTextstring | nullApple and Android: the cancel button.
fallbackTextstring | nullApple: the button shown after a failed match. Null keeps the system "Enter Password" and an empty string hides it. With allowDeviceCredential off, tapping it returns Fallback.
allowDeviceCredentialbooleanAccept the passcode, PIN or pattern too. Windows Hello always offers its PIN.
strengthBiometricStrengthAndroid: the class of biometric accepted.
confirmationRequiredbooleanAndroid: for passive biometrics such as face, wait for the user to confirm after a match.
Response
200 BiometricResult
BiometricResult · 2 fields
statusBiometricResultStatusThe outcome.
errorMessagestring | nullThe platform's own (localized) message for a failure, when it gives one.
Errors
400Bad request409Conflict

JSON property names are camelCase and enums travel as their names. A ? marks a property the payload may omit;| null one that may be null.

BiometricStrengthenum#

Android: the class of biometric asked about or accepted. Apple biometrics are all strong; Windows Hello does not grade them.

"Strong""Weak"
BiometricAvailabilityobject#
statusBiometricStatusWhether biometrics can be used right now.
typesBiometricType[]The hardware present, reported even when nothing is enrolled or biometrics are locked out. Apple reports one type, Android every sensor the device declares, and Windows Unknown.
isDeviceCredentialSetbooleanA passcode, PIN or pattern is set, so allowDeviceCredential has something to fall back to.
BiometricStatusenum#

Whether biometrics can be used right now.

"Available""NotSupported""NotEnrolled""LockedOut""PasscodeNotSet""Unavailable""SecurityUpdateRequired"
BiometricTypeenum#

A kind of biometric hardware.

"Fingerprint""Face""Iris""Unknown"
BiometricRequestobject#
reasonstringWhy the page is asking; shown in the prompt on every platform. Required, at most 256 characters.
title?string | nullAndroid: the prompt title (defaults to reason).
subtitle?string | nullAndroid: a line under the title.
cancelText?string | nullApple and Android: the cancel button.
fallbackText?string | nullApple: the button shown after a failed match. Null keeps the system "Enter Password" and an empty string hides it. With allowDeviceCredential off, tapping it returns Fallback.
allowDeviceCredential?booleanAccept the passcode, PIN or pattern too. Windows Hello always offers its PIN.
strength?BiometricStrengthAndroid: the class of biometric accepted.
confirmationRequired?booleanAndroid: for passive biometrics such as face, wait for the user to confirm after a match.
BiometricResultobject#
statusBiometricResultStatusThe outcome.
errorMessagestring | nullThe platform's own (localized) message for a failure, when it gives one.
BiometricResultStatusenum#

The outcome of a prompt.

"Success""Cancelled""Fallback""Failed""LockedOut""NotEnrolled""PasscodeNotSet""NotAvailable""Timeout"