
windows_hello
Flutter plugin for Windows Hello verification and Windows Credential
Manager (PasswordVault) access.
Use it when your Windows desktop app needs to:
- Confirm the user with face, fingerprint, iris, or Windows Hello PIN
- Store, read, list, and delete secrets in the system Credential Locker
Most APIs return typed results (BiometricAvailability, VerifyResult,
VaultResult) so you can branch on clear outcomes instead of decoding raw
platform channel errors.
Windows only. Android, iOS, macOS, Linux, and Web are not supported.
Features
- Check whether Windows Hello is available on the device
- Show the system Windows Hello prompt with a custom reason string
- Store / overwrite credentials in PasswordVault
- Read, list, and delete credentials by resource and username
- Typed result enums for common success and failure paths
FakeWindowsHelloPlatformfor unit tests without a Windows machine
Supported unlock methods
Windows Hello decides which gesture to show based on what the user has enrolled. This plugin does not let you force a specific method.
| Method | Supported |
|---|---|
| Face | Yes |
| Fingerprint | Yes |
| Iris | Yes |
| Windows Hello PIN | Yes |
| Account password | No |
| Security key (FIDO2) | No |
VerifyResult.verified means the user passed the Hello prompt. Face,
fingerprint, iris, and PIN all return the same verified result — the API does
not report which gesture was used.
Requirements
| Requirement | Value |
|---|---|
| OS | Windows 10 version 1607 (Anniversary Update) or later |
| Flutter | 3.3.0 or later |
| Dart | 3.12.2 or later |
| Hello setup | At least one Windows Hello method enrolled (or PIN) for verification |
Install
dependencies:
windows_hello: ^0.1.0
Then:
flutter pub get
Quick start
import 'package:windows_hello/windows_hello.dart';
final hello = WindowsHello.instance;
// 1. Check availability
final availability = await hello.checkBiometricAvailability();
if (availability != BiometricAvailability.available) {
// Handle not configured / no device / policy, etc.
return;
}
// 2. Prompt Windows Hello
final result = await hello.requestBiometricVerification(
reason: 'Confirm it is you',
);
if (result == VerifyResult.verified) {
// Continue with the protected action.
}
Credential Manager
Secrets are stored in the per-app Windows Credential Locker
(PasswordVault). You can confirm them in
Control Panel → Credential Manager → Windows Credentials.
final hello = WindowsHello.instance;
// Store (overwrites if resource + username already exist)
final stored = await hello.storeCredential(
resource: 'com.example.app',
username: 'alice',
secret: 's3cret',
);
// Read — null means not found
final cred = await hello.readCredential(
resource: 'com.example.app',
username: 'alice',
);
print(cred?.secret);
// List all credentials for a resource
final all = await hello.getAllCredentials(
resource: 'com.example.app',
);
// Delete
final deleted = await hello.deleteCredential(
resource: 'com.example.app',
username: 'alice',
);
Choosing a resource name
Use a stable, app-owned identifier (for example your reverse-DNS package id). Credentials are keyed by resource + username. Storing again with the same pair overwrites the previous secret.
API overview
| Method | Returns | Notes |
|---|---|---|
checkBiometricAvailability() |
BiometricAvailability |
Never throws PlatformException (maps to unknown) |
requestBiometricVerification({reason}) |
VerifyResult |
Never throws PlatformException (maps to unknown) |
storeCredential(...) |
VaultResult |
Overwrites existing resource + username |
deleteCredential(...) |
VaultResult |
notFound when nothing matched |
readCredential(...) |
VaultCredential? |
null = missing; other failures throw PlatformException |
getAllCredentials(...) |
List<VaultCredential> |
Empty list = none; other failures throw PlatformException |
BiometricAvailability
| Value | Meaning |
|---|---|
available |
Hello can be prompted |
deviceNotPresent |
No usable biometric / Hello device |
notConfiguredByUser |
User has not set up Windows Hello |
disabledByPolicy |
Blocked by organization policy |
deviceBusy |
Sensor or Hello UI is busy |
unknown |
Unexpected / channel failure |
VerifyResult
| Value | Meaning |
|---|---|
verified |
User passed the Hello prompt |
canceled |
User dismissed the prompt |
retriesExhausted |
Too many failed attempts |
deviceNotPresent |
No usable device |
notConfiguredByUser |
Hello not set up |
disabledByPolicy |
Blocked by policy |
deviceBusy |
Device busy |
unknown |
Unexpected / channel failure |
VaultResult
| Value | Meaning |
|---|---|
success |
Operation completed |
notFound |
No matching credential (delete) |
accessDenied |
Windows denied access |
unknown |
Unexpected / channel failure |
Error handling
// Biometric APIs — branch on enums
switch (await hello.checkBiometricAvailability()) {
case BiometricAvailability.available:
break;
case BiometricAvailability.notConfiguredByUser:
// Ask the user to set up Windows Hello in Settings.
break;
default:
// Unavailable or unknown.
break;
}
// Vault reads — null vs exception
try {
final cred = await hello.readCredential(
resource: 'com.example.app',
username: 'alice',
);
if (cred == null) {
// Not stored yet.
} else {
// Use cred.secret
}
} on PlatformException catch (e) {
// Access denied or other vault failure — not the same as "missing".
}
Example app
The example/ folder is a Windows desktop demo with:
- Windows Hello availability + verify actions
- Editable PasswordVault resource / username / secret fields
- Plain-language status messages for each result
cd example
flutter run -d windows
Testing
Inject a fake platform — no Windows machine required:
import 'package:flutter_test/flutter_test.dart';
import 'package:windows_hello/windows_hello.dart';
void main() {
test('verification success path', () async {
final fake = FakeWindowsHelloPlatform(
availability: BiometricAvailability.available,
verifyResult: VerifyResult.verified,
);
final hello = WindowsHello(platform: fake);
expect(
await hello.checkBiometricAvailability(),
BiometricAvailability.available,
);
expect(
await hello.requestBiometricVerification(reason: 'test'),
VerifyResult.verified,
);
});
}
When to use local_auth instead
local_auth (via local_auth_windows)
already covers the common “unlock this action with Windows Hello” case and
supports multiple platforms.
Prefer windows_hello when you need:
- PasswordVault / Credential Manager from Flutter (not offered by
local_auth) - Typed availability and verify results without decoding channel errors
- A Windows-only dependency without the full multi-platform
local_authstack
Limitations
- Windows desktop only
- Cannot force face-only / fingerprint-only / PIN-only (system chooses)
- Does not prompt for account password or security keys
- PasswordVault is per-user / per-app; credentials are not shared across apps
- AppContainer apps are limited to 20 credentials in the locker (Windows platform limit)
Privacy
This plugin performs no network calls and collects no telemetry. All
operations stay on-device via WinRT (UserConsentVerifier and
PasswordVault).
Federated packages
| Package | Role |
|---|---|
windows_hello |
App-facing Dart API (this package) |
windows_hello_platform_interface |
Platform interface + Pigeon messages |
windows_hello_windows |
C++/WinRT implementation |
License
See LICENSE.