Skip to content

feat: add wallet authentication layer with WebAuthn and PIN support - #531

Merged
Just-Bamford merged 1 commit into
Sorokit:mainfrom
lajay-faith:feature/wallet-authentication-issue-500
Aug 30, 2026
Merged

feat: add wallet authentication layer with WebAuthn and PIN support#531
Just-Bamford merged 1 commit into
Sorokit:mainfrom
lajay-faith:feature/wallet-authentication-issue-500

Conversation

@lajay-faith

Copy link
Copy Markdown
Contributor

Summary

Implements #500

Adds an application-level authentication layer for wallet access control using WebAuthn (biometric/security key) where available, with PIN-based fallback.

Features

WebAuthn authentication - Biometric and security key support where available
PIN-based fallback - Works everywhere, never stores plaintext PINs
Rate limiting - Protection against brute-force attacks (configurable)
Session management - Configurable timeouts with automatic expiration
Authentication states - Explicit locked/unlocked/expired states
Secure storage - Never exposes private keys or raw biometric data
Backward compatible - Existing wallet connections work without changes
Comprehensive tests - Full coverage of all authentication flows
Complete documentation - Usage guide and API reference

Implementation Details

Architecture

  • Authentication is separate from wallet signing
  • No raw biometric data or private keys are persisted
  • Reuses existing wallet lifecycle patterns
  • Browser-specific limitations are documented

Components

  • WalletAuthenticationManager - Main coordination class
  • PIN Authentication - Hashed storage with salt, 4-8 digit PINs
  • WebAuthn Authentication - Platform and cross-platform authenticator support
  • Rate Limiting - Configurable max attempts and lockout duration
  • Session Management - Timeout-based expiration
  • Storage Adapters - In-memory and localStorage implementations

Security

  • PINs are hashed with random salts (never stored plaintext)
  • WebAuthn private keys never leave the authenticator device
  • Rate limiting prevents brute-force attacks
  • Sessions expire automatically
  • No private wallet material is exposed

Acceptance Criteria

✅ WebAuthn-based authentication is supported where available
✅ PIN setup, verification, change, and reset flows are defined
✅ Failed authentication attempts are rate-limited
✅ Authentication state has explicit locked/unlocked/expired states
✅ Credentials are stored without exposing private wallet material
✅ Unsupported browser capabilities fail gracefully
✅ Tests cover successful, failed, expired, and unsupported authentication flows
✅ Existing wallet connection behavior remains backward compatible

Files Changed

New Files

  • src/wallet/authentication/types.ts - Type definitions
  • src/wallet/authentication/capabilities.ts - Capability detection
  • src/wallet/authentication/pinAuth.ts - PIN authentication
  • src/wallet/authentication/webAuthnAuth.ts - WebAuthn authentication
  • src/wallet/authentication/storage.ts - Storage adapters
  • src/wallet/authentication/authenticationManager.ts - Main coordinator
  • src/wallet/authentication/index.ts - Public API
  • src/wallet/authentication/README.md - Module documentation
  • src/tests/walletAuthentication.test.ts - Comprehensive tests
  • docs/wallet-authentication.md - Complete documentation

Modified Files

  • src/wallet/index.ts - Export authentication module

Usage Example

import { WalletAuthenticationManager, detectAuthenticationCapabilities } from "sorokit-core";

// Detect available authentication methods
const capabilities = await detectAuthenticationCapabilities();

// Create authentication manager
const authManager = new WalletAuthenticationManager({
  sessionTimeoutMs: 900000, // 15 minutes
  maxFailedAttempts: 5,
  rateLimitDurationMs: 300000, // 5 minutes
});

// Setup authentication
if (capabilities.data.webauthn) {
  await authManager.setupWebAuthnAuthentication("wallet-123");
} else {
  await authManager.setupPINAuthentication("wallet-123", { pin: "1234" });
}

// Lock wallet
await authManager.lock("wallet-123");

// Before sensitive operations, require authentication
const authCheck = await authManager.requireAuthentication("wallet-123");
if (authCheck.status === "error") {
  // Unlock wallet
  await authManager.unlock("wallet-123", { method: "PIN", pin: "1234" });
}

// Proceed with wallet operation
await client.wallet.signTransaction(adapter, input);

Testing

All tests pass:

  • PIN setup, verification, change, and reset
  • WebAuthn registration and authentication flows
  • Rate limiting enforcement
  • Session expiration
  • Authentication state transitions
  • Storage integration
  • Error handling
  • Backward compatibility
npm test -- walletAuthentication.test.ts

Browser Compatibility

  • WebAuthn: Chrome 67+, Firefox 60+, Safari 13+, Edge 18+
  • PIN: All environments (Node, browser, React Native)
  • Graceful fallback: Automatically uses PIN when WebAuthn unavailable

Documentation

Complete documentation added:

  • docs/wallet-authentication.md - Full usage guide and API reference
  • src/wallet/authentication/README.md - Module overview

Notes for Reviewers

  • Authentication is completely opt-in and maintains backward compatibility
  • No breaking changes to existing wallet functionality
  • Private keys and biometric data are never stored or exposed
  • Rate limiting and session management provide robust security
  • Comprehensive test coverage ensures reliability

Closes #500

Implements Sorokit#500

- Add WebAuthn-based authentication with biometric/security key support
- Add PIN-based fallback authentication (4-8 digits, hashed storage)
- Implement rate limiting for failed authentication attempts
- Add session management with configurable timeouts
- Support locked/unlocked/expired authentication states
- Provide secure credential storage (never exposes private keys)
- Include comprehensive tests for all authentication flows
- Maintain backward compatibility with existing wallet connections
- Add complete documentation and usage examples

Acceptance Criteria:
✅ WebAuthn-based authentication is supported where available
✅ PIN setup, verification, change, and reset flows are defined
✅ Failed authentication attempts are rate-limited
✅ Authentication state has explicit locked/unlocked/expired states
✅ Credentials are stored without exposing private wallet material
✅ Unsupported browser capabilities fail gracefully
✅ Tests cover successful, failed, expired, and unsupported authentication flows
✅ Existing wallet connection behavior remains backward compatible
@drips-wave

drips-wave Bot commented Aug 29, 2026

Copy link
Copy Markdown

@lajay-faith Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Just-Bamford
Just-Bamford merged commit be5b4b0 into Sorokit:main Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement wallet biometric authentication and PIN protection

2 participants