Flutter Passkey Service - WebAuthn FIDO2 Passwordless Authentication
๐ 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?
- ๐ฑ Live Demo
- โจ Key Features
- ๐ Comparison with Alternatives
- ๐ง Feature Matrix
- ๐ Platform Support
- ๐ Quick Start
- ๐ Comprehensive Guide
- ๐๏ธ Advanced Configuration
- ๐ง Platform Requirements
- ๐งช Testing
- ๐ Security Considerations
- ๐ค Contributing
- ๐ Support
- ๐ Resources
๐ฏ 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 |
---|---|
![]() |
![]() |
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
-
Minimum Requirements: iOS 16.0+
-
Add Capability: In Xcode, add "Associated Domains" capability
- Open your project in Xcode
- Select your target โ "Signing & Capabilities"
- Click "+" and add "Associated Domains"
-
Configure Domain: Add your domain with
webcredentials
prefix:webcredentials:yourdomain.com
-
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
- Host at:
Android Setup
-
Minimum Requirements: Android API 28+ (Android 9.0)
-
Add Dependencies: The plugin automatically includes required dependencies
-
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"] } }]
-
Host Asset Links File:
- Upload to:
https://yourdomain.com/.well-known/assetlinks.json
- Content-Type:
application/json
- Must be accessible via HTTPS
- Upload to:
-
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
-
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)
-
Create the Association File:
{ "webcredentials": { "apps": [ "TEAMID.com.yourcompany.yourapp", "TEAMID.com.yourcompany.yourapp.staging" ] } }
-
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
- URL:
-
Find Your Team ID:
- Go to Apple Developer Account
- Navigate to "Membership" section
- Copy your Team ID (10-character string)
-
Verify Association:
# Test your association file curl -v https://yourdomain.com/.well-known/apple-app-site-association
Android Domain Verification (Digital Asset Links)
-
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
-
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" ] } } ]
-
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
- URL:
-
Verify Asset Links:
# Test your asset links file curl -v https://yourdomain.com/.well-known/assetlinks.json
- Use Google's Tester
- Use Asset Links Generator
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
- Challenge Generation: Always generate challenges server-side using cryptographically secure methods
- Origin Verification: Verify the origin in clientDataJSON matches your domain
- Timeout Handling: Implement appropriate timeouts for user operations
- Error Messages: Avoid exposing sensitive information in error messages
- Credential Storage: Store public keys and metadata securely on your server
- 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
- Documentation: API Reference
- Issues: GitHub Issues
- Discussions: GitHub Discussions
๐ Resources
WebAuthn & Passkeys
- WebAuthn Specification
- Passkeys Overview
- Passkeys.dev - Community resources and guides
Platform Documentation
- iOS AuthenticationServices
- Android Credential Manager
- iOS Passkeys Developer Guide
- Android Passkeys Implementation Guide
Domain Verification Tools
- Apple App Site Association Validator
- Google Digital Asset Links Tester
- Digital Asset Links Generator
- Apple Team ID Lookup
Testing & Debugging
- WebAuthn.io - Test WebAuthn implementations
- Passkeys Debugger - Debug WebAuthn flows
- Yubico WebAuthn Demo - Test various scenarios
Security Resources
- FIDO Alliance - Security specifications and guidelines
- WebAuthn Security Considerations
- OWASP Authentication Guide
๐ 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!
๐ 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