passkey_ui_kit 0.1.0 copy "passkey_ui_kit: ^0.1.0" to clipboard
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.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:passkey_ui_kit/passkey_ui_kit.dart';
import 'package:passkeys/authenticator.dart';

import 'demo_authenticator.dart';
import 'mock_passkey_backend.dart';

void main() => runApp(const PasskeyDemoApp());

/// A single shared in-memory backend so the demo screens see the same passkeys.
final MockPasskeyBackend demoBackend = MockPasskeyBackend();

/// A fake authenticator so the demo runs without biometric hardware. In a real
/// app you'd omit this entirely and let the widgets use the real platform one.
final PasskeyAuthenticator demoAuthenticator = DemoPasskeyAuthenticator();

class PasskeyDemoApp extends StatelessWidget {
  const PasskeyDemoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'passkey_ui_kit demo',
      theme: ThemeData(
        colorSchemeSeed: Colors.indigo,
        useMaterial3: true,
      ),
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  void _snack(BuildContext context, String message) {
    ScaffoldMessenger.of(context)
      ..hideCurrentSnackBar()
      ..showSnackBar(SnackBar(content: Text(message)));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('passkey_ui_kit demo')),
      body: ListView(
        padding: const EdgeInsets.all(20),
        children: [
          Text(
            'This demo uses an in-memory backend and a fake authenticator, so '
            'it runs anywhere with no server and no biometrics.',
            style: Theme.of(context).textTheme.bodyMedium,
          ),
          const SizedBox(height: 24),

          // 1. Onboarding intro screen.
          _DemoTile(
            title: 'Onboarding intro screen',
            subtitle: 'PasskeyIntroScreen',
            onTap: () => Navigator.of(context).push(
              MaterialPageRoute<void>(
                builder: (_) => PasskeyIntroScreen(
                  backend: demoBackend,
                  username: 'ada@example.com',
                  authenticator: demoAuthenticator,
                  onComplete: () {
                    Navigator.of(context).pop();
                    _snack(context, 'Passkey set up 🎉');
                  },
                  onSkip: () => Navigator.of(context).pop(),
                ),
              ),
            ),
          ),

          // 2. Sign-in button + fallback.
          _DemoTile(
            title: 'Sign-in button + fallback',
            subtitle: 'PasskeySignInButton / PasskeyFallbackFlow',
            onTap: () => Navigator.of(context).push(
              MaterialPageRoute<void>(builder: (_) => const SignInDemo()),
            ),
          ),

          // 3. Manage passkeys.
          _DemoTile(
            title: 'Manage passkeys',
            subtitle: 'PasskeyManagementScreen',
            onTap: () => Navigator.of(context).push(
              MaterialPageRoute<void>(
                builder: (_) => PasskeyManagementScreen(
                  backend: demoBackend,
                  username: 'ada@example.com',
                  authenticator: demoAuthenticator,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

/// Demonstrates a login screen: a passkey button with a password form fallback.
class SignInDemo extends StatelessWidget {
  const SignInDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Sign in')),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: PasskeyFallbackFlow(
            authenticator: demoAuthenticator,
            showFallbackAlways: true,
            // `checkAvailability: false` on the button below forces it to show
            // in the simulator; drop it in a real app.
            passkeyWidget: PasskeySignInButton(
              backend: demoBackend,
              authenticator: demoAuthenticator,
              checkAvailability: false,
              onSuccess: (session) {
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text('Signed in! token=${session.token}')),
                );
              },
              onError: (e) {
                ScaffoldMessenger.of(context)
                    .showSnackBar(SnackBar(content: Text(e.userMessage)));
              },
            ),
            fallbackWidget: const _PasswordFormPlaceholder(),
          ),
        ),
      ),
    );
  }
}

class _PasswordFormPlaceholder extends StatelessWidget {
  const _PasswordFormPlaceholder();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        const TextField(
          decoration: InputDecoration(
            labelText: 'Email',
            border: OutlineInputBorder(),
          ),
        ),
        const SizedBox(height: 12),
        const TextField(
          obscureText: true,
          decoration: InputDecoration(
            labelText: 'Password',
            border: OutlineInputBorder(),
          ),
        ),
        const SizedBox(height: 12),
        SizedBox(
          width: double.infinity,
          child: FilledButton.tonal(
            onPressed: () {},
            child: const Text('Sign in with password'),
          ),
        ),
      ],
    );
  }
}

class _DemoTile extends StatelessWidget {
  const _DemoTile({
    required this.title,
    required this.subtitle,
    required this.onTap,
  });

  final String title;
  final String subtitle;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: ListTile(
        title: Text(title),
        subtitle: Text(subtitle),
        trailing: const Icon(Icons.chevron_right),
        onTap: onTap,
      ),
    );
  }
}
1
likes
130
points
9
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Drop-in, themeable UI screens and widgets for passkey (passwordless, biometric) authentication in Flutter. Built on top of the open-source passkeys plugin.

Repository (GitHub)
View/report issues

Topics

#passkeys #webauthn #authentication #biometrics #passwordless

License

MIT (license)

Dependencies

flutter, passkeys

More

Packages that depend on passkey_ui_kit