passkey_ui_kit 0.1.0
passkey_ui_kit: ^0.1.0 copied to clipboard
Drop-in, themeable UI screens and widgets for passkey (passwordless, biometric) authentication in Flutter. Built on top of the open-source passkeys plugin.
passkey_ui_kit #
The UI layer passkeys never had. Drop-in, themeable screens and widgets for passwordless / biometric authentication in Flutter — you bring the backend, we handle the UX.
Why this package #
Passkeys (WebAuthn / FIDO2) are the industry's push to kill passwords — Google,
Apple, and Microsoft are all behind them. Flutter already has an excellent
low-level plugin for the cryptography: passkeys
by Corbado. But that plugin — like every other — leaves the UI/UX entirely to
you. Every team ends up hand-rolling the same screens: an onboarding
explainer, a "sign in with passkey" button, fallback UI for unsupported
devices, and a "manage your passkeys" settings screen.
passkey_ui_kit is the missing UI layer — the same relationship
firebase_ui_auth has to firebase_auth. It sits on top of passkeys
(never reimplementing any cryptography) and gives you polished, themeable,
production-ready widgets.
Features #
| Widget / class | What it does |
|---|---|
PasskeySignInButton |
One-tap "Sign in with Passkey" button with a biometric icon, loading state, and automatic availability gating. |
PasskeyRegisterButton |
"Add a Passkey" button; maps duplicate-registration errors to a friendly message. |
PasskeyIntroScreen |
Full-screen onboarding explainer with fully customizable copy. |
PasskeyFallbackFlow |
Shows your own password/OTP UI when the device can't use passkeys. |
PasskeyManagementScreen |
Settings screen to list / add / remove passkeys. |
PasskeyAuthController |
The engine — drives the flow and exposes reactive state. |
PasskeyAvailability |
Device support detection (PasskeySupportStatus). |
PasskeyUiTheme |
Central theming for every widget. |
PasskeyErrorMessages |
Overridable, localizable error copy. |
Installation #
flutter pub add passkey_ui_kit
Quick start #
1. Implement PasskeyBackend #
This is the only glue code you write. It connects the kit to your WebAuthn relying-party server.
import 'package:passkey_ui_kit/passkey_ui_kit.dart';
class MyPasskeyBackend implements PasskeyBackend {
@override
Future<RegisterOptions> getRegistrationOptions(String username) async {
final json = await api.post('/passkeys/register/options', {'username': username});
return RegisterOptions.fromJson(json); // standard WebAuthn creation options
}
@override
Future<void> finishRegistration(RegisterResponseType response) =>
api.post('/passkeys/register/finish', response.toJson());
@override
Future<AuthenticateOptions> getAuthenticationOptions(String? username) async {
final json = await api.post('/passkeys/login/options', {'username': username});
return AuthenticateOptions.fromJson(json);
}
@override
Future<AuthSession> finishAuthentication(AuthenticateResponseType response) async {
final json = await api.post('/passkeys/login/finish', response.toJson());
return AuthSession(token: json['token'] as String, userId: json['userId'] as String);
}
@override
Future<List<PasskeyInfo>> listPasskeys() async {
final list = await api.get('/passkeys');
return list.map<PasskeyInfo>((e) => PasskeyInfo(
credentialId: e['id'] as String,
label: e['deviceName'] as String?,
createdAt: DateTime.parse(e['createdAt'] as String),
)).toList();
}
@override
Future<void> removePasskey(String credentialId) =>
api.delete('/passkeys/$credentialId');
}
2. Drop in the widgets #
import 'package:passkey_ui_kit/passkey_ui_kit.dart';
final backend = MyPasskeyBackend();
// Onboarding after signup
PasskeyIntroScreen(
backend: backend,
username: user.email,
onComplete: () => Navigator.pushReplacement(context, homeRoute),
);
// Login screen — passkey first, your form as fallback
PasskeyFallbackFlow(
showFallbackAlways: true,
passkeyWidget: PasskeySignInButton(
backend: backend,
onSuccess: (session) => goToHome(session),
onError: (e) => showSnackBar(e.userMessage),
),
fallbackWidget: MyPasswordLoginForm(),
);
// Settings screen
PasskeyManagementScreen(backend: backend, username: user.email);
3. Theme it (optional) #
PasskeySignInButton(
backend: backend,
theme: const PasskeyUiTheme(primaryColor: Colors.deepPurple, borderRadius: 12),
onSuccess: (session) {},
);
Anything you don't set on PasskeyUiTheme inherits from Theme.of(context), so
the widgets blend into your app by default.
Screenshots #
Add screenshots / GIFs of
PasskeyIntroScreen,PasskeySignInButton, andPasskeyManagementScreenhere.
Handling errors #
Every failure surfaces as a typed PasskeyUiException with a ready-to-show
userMessage:
| Exception | When |
|---|---|
PasskeyCancelledException |
User dismissed the biometric prompt (treat as a no-op). |
PasskeyUnsupportedException |
Device can't use passkeys — fall back. |
PasskeyNoCredentialsException |
No passkey on this device for the account. |
PasskeyDuplicateException |
A passkey already exists on the device. |
PasskeyBackendException |
Your PasskeyBackend call failed. |
PasskeyUnknownException |
Anything else. |
Localize the copy by passing a PasskeyErrorMessages to any widget.
You need a relying-party server #
This package is a UI layer only — it never hosts or replaces a WebAuthn
relying-party server. Your PasskeyBackend must call one. If you don't have one
yet, see:
For local development and to try this package without any server, see the
example/ app — it ships with an in-memory MockPasskeyBackend.
Requirements #
- Flutter
>= 3.22.0, Dart>= 3.4.0 - Android API 28+ / iOS 16+ for full passkey support (the kit degrades
gracefully below that via
PasskeyFallbackFlow)
License #
MIT — see LICENSE.