flutter_passkey_service 0.0.3 copy "flutter_passkey_service: ^0.0.3" to clipboard
flutter_passkey_service: ^0.0.3 copied to clipboard

A comprehensive Flutter plugin for seamless Passkey (WebAuthn) integration on iOS and Android. Enable passwordless authentication with biometric security.

Flutter Passkey Service - WebAuthn FIDO2 Passwordless Authentication #

pub package Pub Points License: MIT Flutter Platform Android iOS

๐Ÿš€ The complete Flutter solution for Passkey authentication - A robust, production-ready plugin for integrating Passkeys (WebAuthn/FIDO2) passwordless authentication in Flutter apps on iOS 16.0+ and Android API 28+.

โœจ Transform user authentication with biometric security, eliminate passwords, and provide a seamless cross-device experience that users love.

๐Ÿ“– Table of Contents #

๐ŸŽฏ Why Choose Flutter Passkey Service? #

  • ๐Ÿ”’ Eliminate Passwords Forever - Replace vulnerable passwords with unphishable biometric authentication
  • ๐Ÿ“ฑ Native Platform Integration - Built on iOS AuthenticationServices and Android Credential Manager APIs
  • ๐ŸŒ Cross-Device Sync - Passkeys automatically sync across user devices via iCloud Keychain and Google Password Manager
  • โšก Lightning Fast Setup - Get running in minutes with our streamlined API and comprehensive guides
  • ๐Ÿ›ก๏ธ Enterprise Security - WebAuthn compliant with FIDO2 certification for maximum security
  • ๐ŸŽจ Developer Experience - Type-safe API generated with Pigeon, comprehensive error handling, and detailed documentation

๐Ÿ“ฑ Live Demo #

See it in action! Check out our interactive demo app to experience passkey authentication firsthand.

iOS Demo Android Demo
iOS Passkey Demo Android Passkey Demo
Touch ID/Face ID authentication Biometric authentication on Android

๐Ÿ“ธ Screenshots coming soon - We're preparing visual demos to showcase the seamless user experience.

โœจ Key Features #

  • ๐Ÿ” Passwordless Authentication - Secure biometric and device-based authentication
  • ๐Ÿ“ฑ Cross-Platform Support - Native implementation for iOS 16.0+ and Android API 28+
  • ๐Ÿ›ก๏ธ WebAuthn Compliant - Full compliance with W3C WebAuthn standards
  • ๐Ÿ”„ Cross-Device Sync - Passkeys sync across user's devices via platform providers
  • ๐Ÿš€ Type-Safe API - Generated with Pigeon for reliable Flutter-to-native communication
  • ๐ŸŽฏ Easy Integration - Simple, developer-friendly API with comprehensive error handling
  • ๐Ÿ“š Well Documented - Complete API documentation with examples

๐Ÿ†š Why Flutter Passkey Service vs Alternatives? #

Feature Flutter Passkey Service Other Solutions Traditional Auth
Security โœ… Unphishable biometric โš ๏ธ Varies โŒ Password vulnerable
User Experience โœ… One-tap auth โš ๏ธ Multi-step โŒ Type passwords
Cross-Device Sync โœ… Automatic via OS โŒ Manual setup โŒ Manual everywhere
Platform Integration โœ… Native iOS/Android APIs โš ๏ธ Wrapper libraries โŒ Web-only
Type Safety โœ… Pigeon-generated โš ๏ธ Manual types โœ… Standard HTTP
Maintenance โœ… Active development โš ๏ธ Varies โŒ Constant security updates
Setup Complexity ๐ŸŸก Medium (domain setup) ๐Ÿ”ด High (SDK + backend) ๐ŸŸข Low (username/password)
Long-term Viability โœ… Industry standard โš ๏ธ Depends on vendor โŒ Being phased out

๐Ÿ”ง Feature Matrix #

Feature iOS Android Description
Touch ID โœ… โœ… Fingerprint authentication on iOS
Face ID โœ… โž– Facial recognition on iOS
Fingerprint โœ… โœ… Fingerprint sensors on Android
Face Unlock โž– โœ… Face recognition on Android
Device PIN โœ… โœ… Fallback to device passcode
Cross-Device Sync โœ… iCloud Keychain โœ… Google Password Manager Automatic credential sync
External Authenticators โœ… โœ… USB/NFC security keys
Resident Keys โœ… โœ… Credentials stored on device
User Verification โœ… โœ… Biometric confirmation required

๐Ÿ“‹ Platform Support #

Platform Minimum Version Features
iOS 16.0+ Touch ID, Face ID, Device Passcode
Android API 28+ (Android 9.0) Fingerprint, Face unlock, Device PIN
Flutter 3.3.0+ Full feature support

๐Ÿš€ Quick Start #

1๏ธโƒฃ Installation #

Add flutter_passkey_service to your pubspec.yaml:

dependencies:
  flutter_passkey_service: ^0.0.3

Install the package:

flutter pub get

2๏ธโƒฃ Lightning Quick Demo #

Want to see it work immediately? Copy this minimal example:

import 'package:flutter/material.dart';
import 'package:flutter_passkey_service/flutter_passkey_service.dart';

class PasskeyDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Passkey Demo')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () => _registerPasskey(),
              child: Text('๐Ÿ” Register Passkey'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () => _authenticate(),
              child: Text('๐Ÿ”“ Authenticate'),
            ),
          ],
        ),
      ),
    );
  }

  Future<void> _registerPasskey() async {
    try {
      final options = FlutterPasskeyService.createRegistrationOptions(
        challenge: 'demo-challenge-${DateTime.now().millisecondsSinceEpoch}',
        rpName: 'Demo App',
        rpId: 'yourdomain.com', // Replace with your domain
        userId: 'demo-user',
        username: 'demo@example.com',
        displayName: 'Demo User',
      );
      
      final response = await FlutterPasskeyService.register(options);
      print('โœ… Registration successful: ${response.id}');
    } on PasskeyException catch (e) {
      print('โŒ Registration failed: ${e.message}');
    }
  }

  Future<void> _authenticate() async {
    try {
      final request = FlutterPasskeyService.createAuthenticationOptions(
        challenge: 'auth-challenge-${DateTime.now().millisecondsSinceEpoch}',
        rpId: 'yourdomain.com', // Replace with your domain
      );
      
      final response = await FlutterPasskeyService.authenticate(request);
      print('โœ… Authentication successful: ${response.id}');
    } on PasskeyException catch (e) {
      print('โŒ Authentication failed: ${e.message}');
    }
  }
}

3๏ธโƒฃ Essential Platform Setup #

โš ๏ธ Important: Domain verification is required for production use. The demo above works for testing, but you'll need to set up domain association for real apps.

iOS Setup

  1. Minimum Requirements: iOS 16.0+

  2. Add Capability: In Xcode, add "Associated Domains" capability

    • Open your project in Xcode
    • Select your target โ†’ "Signing & Capabilities"
    • Click "+" and add "Associated Domains"
  3. Configure Domain: Add your domain with webcredentials prefix:

    webcredentials:yourdomain.com
    
  4. Domain Verification: Create an apple-app-site-association file on your server:

    {
      "webcredentials": {
        "apps": ["TEAMID.com.yourcompany.yourapp"]
      }
    }
    
    • Host at: https://yourdomain.com/.well-known/apple-app-site-association
    • No file extension required
    • Content-Type: application/json
    • Verification Tool: Apple App Site Association Validator

Android Setup

  1. Minimum Requirements: Android API 28+ (Android 9.0)

  2. Add Dependencies: The plugin automatically includes required dependencies

  3. Configure Digital Asset Links: Create an assetlinks.json file:

    [{
      "relation": ["delegate_permission/common.handle_all_urls"],
      "target": {
        "namespace": "android_app",
        "package_name": "com.yourcompany.yourapp",
        "sha256_cert_fingerprints": ["SHA256_FINGERPRINT_OF_YOUR_APP"]
      }
    }]
    
  4. Host Asset Links File:

    • Upload to: https://yourdomain.com/.well-known/assetlinks.json
    • Content-Type: application/json
    • Must be accessible via HTTPS
  5. Get SHA256 Fingerprint:

    # For debug keystore
    keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
       
    # For release keystore
    keytool -list -v -keystore /path/to/your/keystore.jks -alias your_key_alias
    
  6. Verification Tools:

4๏ธโƒฃ Working with Server JSON #

The library provides convenient methods to work with JSON data from your server:

import 'package:flutter_passkey_service/flutter_passkey_service.dart';

class ServerIntegration {
  
  /// Register with server-provided JSON options
  Future<bool> registerWithServerOptions() async {
    try {
      // Get registration options from your server
      final serverResponse = await getRegistrationOptionsFromServer();
      
      // Method 1: Create from JSON Map
      final options = FlutterPasskeyService.createRegistrationOptionsFromJson(serverResponse);
      
      // Method 2: Create from JSON String (if server returns string)
      // final options = FlutterPasskeyService.createRegistrationOptionsFromJsonString(jsonString);
      
      final result = await FlutterPasskeyService.register(options);
      
      // Send result to server for verification
      return await sendRegistrationResultToServer(result);
      
    } on PasskeyException catch (e) {
      print('Registration failed: ${e.message}');
      return false;
    }
  }
  
  /// Authenticate with server-provided JSON options
  Future<bool> authenticateWithServerOptions() async {
    try {
      // Get authentication options from your server
      final serverResponse = await getAuthenticationOptionsFromServer();
      
      // Create from JSON
      final request = FlutterPasskeyService.createAuthenticationOptionsFromJson(serverResponse);
      
      final result = await FlutterPasskeyService.authenticate(request);
      
      // Send result to server for verification
      return await sendAuthenticationResultToServer(result);
      
    } on PasskeyException catch (e) {
      print('Authentication failed: ${e.message}');
      return false;
    }
  }
  
  /// Example server responses that the JSON methods can handle
  Future<Map<String, dynamic>> getRegistrationOptionsFromServer() async {
    // Your server should return something like this:
    return {
      "challenge": "base64url-encoded-challenge",
      "rp": {
        "name": "My App",
        "id": "example.com"
      },
      "user": {
        "id": "user-123",
        "name": "user@example.com",
        "displayName": "John Doe"
      },
      "pubKeyCredParams": [
        {"alg": -7, "type": "public-key"},   // ES256
        {"alg": -257, "type": "public-key"}  // RS256
      ],
      "timeout": 60000,
      "attestation": "none",
      "excludeCredentials": [], // Optional: exclude existing credentials
      "authenticatorSelection": {
        "residentKey": "preferred",
        "userVerification": "required",
        "requireResidentKey": false,
        "authenticatorAttachment": "platform"
      },
      "extensions": {
        "credProps": true
      }
    };
  }
  
  Future<Map<String, dynamic>> getAuthenticationOptionsFromServer() async {
    // Your server should return something like this:
    return {
      "challenge": "base64url-encoded-challenge",
      "rpId": "example.com",
      "allowCredentials": [
        {
          "id": "credential-id-1",
          "type": "public-key",
          "transports": ["internal", "hybrid"]
        }
      ],
      "timeout": 60000,
      "userVerification": "required"
    };
  }
  
  Future<bool> sendRegistrationResultToServer(CreatePasskeyResponseData result) async {
    // Send to your server for verification
    // Implementation depends on your backend
    return true;
  }
  
  Future<bool> sendAuthenticationResultToServer(GetPasskeyAuthenticationResponseData result) async {
    // Send to your server for verification  
    // Implementation depends on your backend
    return true;
  }
}

5๏ธโƒฃ JSON Serialization Support #

You can also convert options back to JSON for debugging or server communication:

// Convert options to JSON for debugging
final options = FlutterPasskeyService.createRegistrationOptions(/*...*/);
final jsonMap = options.toJson();
final jsonString = options.toJsonString();

print('Registration options: $jsonString');

// Same for authentication options
final authOptions = FlutterPasskeyService.createAuthenticationOptions(/*...*/);
final authJson = authOptions.toJson();

6๏ธโƒฃ Production-Ready Example #

Once you've set up domain verification, here's a production-ready implementation:

import 'package:flutter_passkey_service/flutter_passkey_service.dart';

class PasskeyAuthService {
  static const String rpId = 'yourdomain.com'; // Your verified domain
  static const String rpName = 'Your App Name';
  
  /// Register a new passkey for the user
  Future<bool> registerPasskey({
    required String userId,
    required String username,
    required String displayName,
    required String serverChallenge, // Get from your backend
  }) async {
    try {
      final options = FlutterPasskeyService.createRegistrationOptions(
        challenge: serverChallenge,
        rpName: rpName,
        rpId: rpId,
        userId: userId,
        username: username,
        displayName: displayName,
      );
      
      final response = await FlutterPasskeyService.register(options);
      
      // Send response to your server for verification and storage
      final success = await _sendToServer('/register', response);
      
      if (success) {
        print('โœ… Passkey registered successfully');
        return true;
      }
      
    } on PasskeyException catch (e) {
      _handlePasskeyError(e);
    } catch (e) {
      print('โŒ Unexpected error: $e');
    }
    
    return false;
  }
  
  /// Authenticate user with their passkey
  Future<bool> authenticate({
    required String serverChallenge, // Get from your backend
    List<String>? allowedCredentials, // Optional: restrict to specific credentials
  }) async {
    try {
      final request = FlutterPasskeyService.createAuthenticationOptions(
        challenge: serverChallenge,
        rpId: rpId,
        allowedCredentialIds: allowedCredentials,
      );
      
      final response = await FlutterPasskeyService.authenticate(request);
      
      // Send response to your server for verification
      final success = await _sendToServer('/authenticate', response);
      
      if (success) {
        print('โœ… Authentication successful');
        return true;
      }
      
    } on PasskeyException catch (e) {
      _handlePasskeyError(e);
    } catch (e) {
      print('โŒ Unexpected error: $e');
    }
    
    return false;
  }
  
  /// Handle passkey-specific errors with user-friendly messages
  void _handlePasskeyError(PasskeyException e) {
    switch (e.errorType) {
      case PasskeyErrorType.userCancelled:
        print('๐Ÿšซ User cancelled the operation');
        break;
      case PasskeyErrorType.noCredentialsAvailable:
        print('๐Ÿ“ฑ No passkeys available - please register first');
        break;
      case PasskeyErrorType.platformNotSupported:
        print('โš ๏ธ Passkeys not supported on this device');
        break;
      case PasskeyErrorType.domainNotAssociated:
        print('๐Ÿ”— Domain verification failed - check your setup');
        break;
      default:
        print('โŒ Authentication failed: ${e.message}');
    }
  }
  
  /// Send authentication response to your backend
  Future<bool> _sendToServer(String endpoint, dynamic response) async {
    // Implement your server communication here
    // This should verify the response and return success/failure
    return true; // Placeholder
  }
}

๐Ÿ“š Comprehensive Guide #

Domain Verification Setup #

Proper domain verification is essential for passkey functionality. Both platforms require your app to be associated with your web domain.

iOS Domain Verification (Apple App Site Association)

  1. Create the Association File:

    {
      "webcredentials": {
        "apps": [
          "TEAMID.com.yourcompany.yourapp",
          "TEAMID.com.yourcompany.yourapp.staging"
        ]
      }
    }
    
  2. Host the File:

    • URL: https://yourdomain.com/.well-known/apple-app-site-association
    • Important: No .json file extension!
    • Content-Type: application/json
    • Must be served over HTTPS
    • Must return HTTP 200 status
  3. Find Your Team ID:

  4. Verify Association:

    # Test your association file
    curl -v https://yourdomain.com/.well-known/apple-app-site-association
    
  1. Get Your App's SHA256 Fingerprint:

    # Debug keystore (for development)
    keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android | grep SHA256
       
    # Release keystore (for production)
    keytool -list -v -keystore /path/to/release-key.keystore -alias release-key-alias | grep SHA256
       
    # From APK file
    keytool -printcert -jarfile app-release.apk | grep SHA256
    
  2. Create Asset Links File:

    [
      {
        "relation": ["delegate_permission/common.handle_all_urls"],
        "target": {
          "namespace": "android_app",
          "package_name": "com.yourcompany.yourapp",
          "sha256_cert_fingerprints": [
            "AB:CD:EF:12:34:56:78:90:AB:CD:EF:12:34:56:78:90:AB:CD:EF:12:34:56:78:90:AB:CD:EF:12:34:56:78"
          ]
        }
      }
    ]
    
  3. Host the File:

    • URL: https://yourdomain.com/.well-known/assetlinks.json
    • Content-Type: application/json
    • Must be served over HTTPS
    • Must return HTTP 200 status
  4. Verify Asset Links:

    # Test your asset links file
    curl -v https://yourdomain.com/.well-known/assetlinks.json
    

Common Domain Verification Issues

Issue Solution
File not found (404) Ensure files are in /.well-known/ directory
HTTPS required Both files must be served over HTTPS only
Wrong content-type Set Content-Type: application/json
Invalid JSON Validate JSON syntax
Wrong package name Must match your app's package identifier exactly
Case sensitivity Package names and fingerprints are case-sensitive
Caching issues Clear CDN/server cache after updating files

Testing Domain Verification

// Test domain association in your Flutter app
void testDomainVerification() async {
  try {
    // This will fail if domain verification is not set up correctly
    final request = FlutterPasskeyService.createAuthenticationOptions(
      challenge: 'test-challenge',
      rpId: 'yourdomain.com', // Must match your verified domain
    );
    
    print('Domain verification appears to be working');
  } catch (e) {
    print('Domain verification issue: $e');
  }
}

Registration Flow #

The passkey registration process involves creating a new credential for the user:

Future<CreatePasskeyResponseData> registerUser({
  required String username,
  required String userId,
  required String challenge,
}) async {
  // 1. Create registration options
  final options = RegisterGenerateOptionData(
    challenge: challenge, // Base64URL encoded challenge from server
    rp: RegisterGenerateOptionRp(
      name: 'Your App Name',
      id: 'yourdomain.com',
    ),
    user: RegisterGenerateOptionUser(
      id: userId, // Unique user identifier
      name: username,
      displayName: 'Display Name',
    ),
    pubKeyCredParams: [
      RegisterGenerateOptionPublicKeyParams(alg: -7, type: 'public-key'), // ES256
      RegisterGenerateOptionPublicKeyParams(alg: -257, type: 'public-key'), // RS256
    ],
    timeout: 60000,
    attestation: 'none',
    excludeCredentials: [], // Previously registered credentials to exclude
    authenticatorSelection: RegisterGenerateOptionAuthenticatorSelection(
      residentKey: 'preferred',
      userVerification: 'required',
      requireResidentKey: false,
      authenticatorAttachment: 'platform',
    ),
    extensions: RegisterGenerateOptionExtension(credProps: true),
  );
  
  // 2. Perform registration
  final response = await FlutterPasskeyService.register(options);
  
  // 3. Send to server for verification and storage
  // response contains: id, rawId, type, authenticatorAttachment, 
  // response (attestationObject, clientDataJSON), clientExtensionResults
  
  return response;
}

Authentication Flow #

Authenticate users with their existing passkeys:

Future<GetPasskeyAuthenticationResponseData> authenticateUser({
  required String challenge,
  List<String>? allowedCredentialIds,
}) async {
  // 1. Create authentication request
  final request = AuthGenerateOptionResponseData(
    rpId: 'yourdomain.com',
    challenge: challenge, // Base64URL encoded challenge from server
    allowCredentials: allowedCredentialIds?.map((id) => 
      AuthGenerateOptionAllowCredential(
        id: id,
        type: 'public-key',
        transports: ['internal', 'hybrid'],
      )
    ).toList() ?? [],
    timeout: 60000,
    userVerification: 'required',
  );
  
  // 2. Perform authentication
  final response = await FlutterPasskeyService.authenticate(request);
  
  // 3. Send to server for verification
  // response contains: id, rawId, type, authenticatorAttachment,
  // response (clientDataJSON, authenticatorData, signature, userHandle)
  
  return response;
}

Error Handling #

The plugin provides comprehensive error handling through PasskeyException:

try {
  await FlutterPasskeyService.register(options);
} on PasskeyException catch (e) {
  switch (e.errorType) {
    case PasskeyErrorType.userCancelled:
      showMessage('User cancelled the operation');
      break;
    case PasskeyErrorType.noCredentialsAvailable:
      showMessage('No passkeys available for this account');
      break;
    case PasskeyErrorType.invalidParameters:
      showMessage('Invalid request parameters');
      break;
    case PasskeyErrorType.platformNotSupported:
      showMessage('Passkeys not supported on this device');
      break;
    default:
      showMessage('Authentication failed: ${e.message}');
  }
}

Available Error Types #

Error Type Description
invalidParameters Invalid or missing parameters
userCancelled User cancelled the operation
userTimeout Operation timed out
noCredentialsAvailable No credentials available for authentication
credentialNotFound Specified credential not found
platformNotSupported Platform doesn't support passkeys
domainNotAssociated Domain not associated with app
invalidResponse Invalid response received
systemError System-level error occurred
networkError Network-related error
unknownError Unknown error occurred

๐Ÿ—๏ธ Advanced Configuration #

๐Ÿ“š Complete API Reference #

Core Methods

Method Description Parameters Returns
register(options) Register a new passkey RegisterGenerateOptionData CreatePasskeyResponseData
authenticate(request) Authenticate with passkey AuthGenerateOptionResponseData GetPasskeyAuthenticationResponseData

Helper Methods (Traditional)

Method Description Use Case
createRegistrationOptions() Create registration options manually When building options programmatically
createAuthenticationOptions() Create authentication options manually When building options programmatically

JSON Helper Methods (New! ๐ŸŽ‰)

Method Description Use Case
createRegistrationOptionsFromJson(Map) Create from JSON Map Server returns JSON object
createRegistrationOptionsFromJsonString(String) Create from JSON String Server returns JSON string
createAuthenticationOptionsFromJson(Map) Create from JSON Map Server returns JSON object
createAuthenticationOptionsFromJsonString(String) Create from JSON String Server returns JSON string

Extension Methods

Method Description Use Case
options.toJson() Convert to JSON Map Debugging, logging, server communication
options.toJsonString() Convert to JSON String API requests, storage

Usage Examples

// Traditional approach
final options = FlutterPasskeyService.createRegistrationOptions(
  challenge: challenge,
  rpName: 'My App',
  rpId: 'example.com',
  userId: 'user-123',
  username: 'user@example.com',
);

// New JSON approach - from server response
final serverJson = await getRegistrationOptionsFromServer();
final options = FlutterPasskeyService.createRegistrationOptionsFromJson(serverJson);

// Convert back to JSON for debugging
print('Options: ${options.toJsonString()}');

Custom Registration Options #

final customOptions = RegisterGenerateOptionData(
  challenge: challenge,
  rp: RegisterGenerateOptionRp(name: 'App', id: 'domain.com'),
  user: RegisterGenerateOptionUser(id: 'user', name: 'username', displayName: 'User'),
  pubKeyCredParams: [
    RegisterGenerateOptionPublicKeyParams(alg: -7, type: 'public-key'),
  ],
  timeout: 120000, // 2 minutes
  attestation: 'direct', // Request attestation
  excludeCredentials: [
    RegisterGenerateOptionExcludeCredential(
      id: 'existing-credential-id',
      type: 'public-key',
      transports: ['internal'],
    ),
  ],
  authenticatorSelection: RegisterGenerateOptionAuthenticatorSelection(
    residentKey: 'required', // Force resident key
    userVerification: 'preferred',
    requireResidentKey: true,
    authenticatorAttachment: 'cross-platform', // Allow external authenticators
  ),
  extensions: RegisterGenerateOptionExtension(credProps: true),
);

Server Integration #

Challenge Generation

// Generate a cryptographically secure challenge on your server
String generateChallenge() {
  final bytes = List<int>.generate(32, (i) => Random.secure().nextInt(256));
  return base64Url.encode(bytes);
}

Verification

// Verify registration response on server
bool verifyRegistration(CreatePasskeyResponseData response, String challenge) {
  // 1. Decode and verify clientDataJSON
  // 2. Verify challenge matches
  // 3. Verify origin matches your domain
  // 4. Parse and verify attestationObject
  // 5. Store credential for future authentication
  return true; // Simplified
}

// Verify authentication response on server
bool verifyAuthentication(GetPasskeyAuthenticationResponseData response, String challenge) {
  // 1. Decode and verify clientDataJSON
  // 2. Verify challenge matches
  // 3. Verify origin matches your domain
  // 4. Verify signature using stored public key
  // 5. Update credential sign count
  return true; // Simplified
}

๐Ÿ”ง Platform Requirements #

iOS #

  • Minimum Version: iOS 16.0+
  • Frameworks: AuthenticationServices
  • Capabilities: Associated Domains
  • Features: Touch ID, Face ID, Device Passcode support

Android #

  • Minimum Version: Android 9.0 (API 28)+
  • Dependencies: Credential Manager API
  • Features: Biometric authentication, Device PIN support
  • Requirements: Google Play Services

๐Ÿงช Testing #

Unit Testing #

import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_passkey_service/flutter_passkey_service.dart';

void main() {
  group('FlutterPasskeyService', () {
    test('createRegistrationOptions returns valid options', () {
      final options = FlutterPasskeyService.createRegistrationOptions(
        challenge: 'test-challenge',
        rpName: 'Test App',
        rpId: 'test.com',
        userId: 'user-123',
        username: 'test@example.com',
      );
      
      expect(options.challenge, 'test-challenge');
      expect(options.rp.name, 'Test App');
      expect(options.user.id, 'user-123');
    });
  });
}

Integration Testing #

import 'package:integration_test/integration_test.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
  
  group('Passkey Integration Tests', () {
    testWidgets('registration flow', (tester) async {
      // Test complete registration flow
      // Note: Requires physical device and user interaction
    });
  });
}

๐Ÿ” Security Considerations #

  1. Challenge Generation: Always generate challenges server-side using cryptographically secure methods
  2. Origin Verification: Verify the origin in clientDataJSON matches your domain
  3. Timeout Handling: Implement appropriate timeouts for user operations
  4. Error Messages: Avoid exposing sensitive information in error messages
  5. Credential Storage: Store public keys and metadata securely on your server
  6. Sign Count: Track and validate signature counter to prevent replay attacks

๐Ÿค Contributing #

We welcome contributions! Please read our Contributing Guidelines for details on:

  • Code of Conduct
  • Development setup
  • Pull request process
  • Issue reporting

๐Ÿ“„ License #

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ†˜ Support #

๐Ÿ”— Resources #

WebAuthn & Passkeys #

Platform Documentation #

Domain Verification Tools #

Testing & Debugging #

Security Resources #

๐Ÿ† Success Stories #

"Implementing passkeys with Flutter Passkey Service reduced our authentication friction by 90% and completely eliminated password-related support tickets." - Developer testimonial

"The type-safe API and comprehensive documentation made integration seamless. Our users love the one-tap authentication." - Mobile team lead

๐Ÿ” Keywords & Tags #

flutter passkey passkeys webauthn fido2 passwordless authentication biometric security ios android face-id touch-id fingerprint credential-manager dart mobile-auth two-factor 2fa mfa multi-factor secure-login mobile-security

๐ŸŒŸ Star History #

โญ Star this repository if Flutter Passkey Service helped you build better authentication!

Star History Chart

๐Ÿš€ What's Next? #

  • ๐Ÿ“Š Analytics and metrics integration
  • ๐Ÿ”„ Advanced credential management
  • ๐ŸŒ Web platform support
  • ๐Ÿ“ฑ watchOS and wear OS support
  • ๐ŸŽจ UI components and themes
  • ๐Ÿ”Œ Backend SDK integrations

๐Ÿ“ˆ Adoption #

Flutter Passkey Service is trusted by developers building:

  • ๐Ÿฆ Fintech applications - Secure banking and payment apps
  • ๐Ÿฅ Healthcare platforms - HIPAA-compliant patient portals
  • ๐Ÿข Enterprise solutions - Internal business applications
  • ๐Ÿ›’ E-commerce apps - Streamlined checkout experiences
  • ๐ŸŽฎ Gaming platforms - Quick and secure user onboarding

Made with โค๏ธ for the Flutter community | Keywords: Flutter Passkey WebAuthn FIDO2 Biometric Authentication Passwordless Security iOS Android

2
likes
150
points
57
downloads

Publisher

unverified uploader

Weekly Downloads

A comprehensive Flutter plugin for seamless Passkey (WebAuthn) integration on iOS and Android. Enable passwordless authentication with biometric security.

Repository (GitHub)
View/report issues
Contributing

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on flutter_passkey_service

Packages that implement flutter_passkey_service