Skip to content

Conversation

@kkalass
Copy link

@kkalass kkalass commented Oct 29, 2025

🚀 Overview

Adds worker thread support for DPoP token generation, enabling better performance by offloading cryptographic operations from the main thread to Dart isolates or web workers.

Dependencies

⚠️ This PR depends on #24
Please review and merge #24 (feat/migrate-to-bdaya-oidc-security-fix) first, as this PR builds on top of those changes.

The diff will look large because it includes commits from the base PR, but only the last commit (feat: add worker thread support) is new.

✨ What's New

API

// Export credentials for worker thread
final credentials = solidAuth.exportDpopCredentials();

// Generate DPoP token in isolate
void workerFunction(Map<String, dynamic> json) {
  final credentials = DpopCredentials.fromJson(json);
  final dpop = credentials.generateDpopToken(url: url, method: 'GET');
}

await Isolate.spawn(workerFunction, credentials.toJson());

Key Features

  • DpopCredentials class: Immutable, serializable container for RSA keys and access tokens
  • exportDpopCredentials(): Export method on SolidAuth and SolidOidcUserManager
  • generateDpopToken(): Instance method for thread-safe token generation
  • Security model: Clear intra-process (✅ safe) vs. external transfer (❌ unsafe) documentation

🔒 Security

Credentials transfer is safe because:

  • Stays within OS-protected process boundary
  • Standard practice in multi-threaded crypto (OpenSSL, BoringSSL)
  • Comprehensive docs distinguish safe (isolates, compute()) from unsafe (network, storage) usage

📚 Files Added

  • doc/dpop_worker_threads.md: Complete security model, API reference, usage examples
  • example/dpop_worker_example.dart: Working isolate example with error handling
  • test/dpop_credentials_test.dart: 7 tests covering serialization, immutability, generation

🎯 When to Use

Worker threads: Many concurrent tokens, main thread responsiveness critical, profiling shows bottleneck
Main thread: Few tokens, simplicity preferred (sufficient for most apps)

📦 Changes

  • Modified: lib/src/oidc/solid_oidc_user_manager.dart - Added DpopCredentials class, export method
  • Modified: lib/src/solid_auth.dart - Added wrapper export method
  • Added: Documentation, example, tests (~425 lines total)

Note: Advanced optimization feature. Most apps should use solidAuth.genDpopToken() unless profiling shows DPoP generation as bottleneck.

kkalass and others added 11 commits August 3, 2025 20:57
This PR migrates the authentication system from the custom OpenID Connect
implementation to the well-maintained oidc library, addressing several
security and maintainability concerns.

Key changes:
- Replace custom OpenID client with oidc library for better security
- Add reactive authentication state management with ValueNotifier
- Implement proper DPoP token handling through oidc hooks
- Refactor example app to demonstrate new authentication patterns
- Add client-profile.jsonld for Solid OIDC compliance
- Update dependencies and remove unnused packages

Breaking changes:
- New SolidAuth class replaces previous authenticate() function
- Authentication state is now reactive via isAuthenticatedNotifier
- DPoP token generation integrated into authentication flow

This migration improves security, reduces maintenance burden, and provides
a more modern Flutter-friendly API while maintaining full Solid OIDC
compatibility. The changes have been tested with the example application.

Resolves authentication reliability issues and provides a foundation for
future enhancements to the library.
… offline_access

Previously, Solid OIDC authentication failed to obtain refresh tokens because
the required 'consent' prompt wasn't sent to identity providers. This change
automatically adds the consent prompt when offline_access is in the requested
scopes, enabling proper token refresh and persistent authentication.

Includes configurable prompt calculation and comprehensive test coverage.
- Change default value of strictJwtVerification from false to true
- Update documentation to reflect security-first approach
- Add security warnings for disabling strict verification
- Remove redundant examples showing explicit true value
During refresh, apparently we do not have headers on the request, so we need to set it to an empty map
Added required network permissions documentation to README:
- Android: INTERNET permission in AndroidManifest.xml
- macOS: com.apple.security.network.client entitlement

These permissions are essential for Solid authentication to work
properly when connecting to identity providers and pod servers.

Co-Authored-By: Claude <noreply@anthropic.com>
Add DpopCredentials class for safe intra-process transfer of cryptographic
material to Dart isolates and web workers. This enables offloading DPoP
token generation to worker threads for improved performance in high-
throughput scenarios.

- DpopCredentials: Immutable, serializable class with RSA keys and access token
- exportDpopCredentials(): Export credentials from SolidAuth/SolidOidcUserManager
- generateDpopToken(): Instance method on DpopCredentials for token generation
- Comprehensive security documentation explaining intra-process trust model
- Complete isolate example (example/dpop_worker_example.dart)
- Test coverage (7 tests for DpopCredentials)

The security model is based on standard practice in multi-threaded crypto
libraries: credentials stay within the OS-protected process boundary.
PROBLEM:
DPoP credentials needed to be transferred to web workers and isolates for
performance-optimized token generation. However, using fast_rsa's KeyPair
class in our serializable DpopCredentials prevented this because fast_rsa
types depend on platform-specific code (platform channels on native,
WebAssembly on web) that is unavailable in worker contexts.

The root cause was subtle but simple: we never actually needed to *call*
fast_rsa methods in workers - we only needed to *use* the KeyPair type to
store PEM strings. The dependency on the fast_rsa.KeyPair type itself was
the blocker.

SOLUTION:
Introduce a clean abstraction layer that isolates fast_rsa to key generation:

1. Created platform-agnostic types in rsa_api.dart:
   - KeyPair: Simple PEM string container (no platform dependencies)
   - GeneratedRsaKeyPair: Complete generation result with JWK
   - RsaCrypto: Abstract interface for key generation

2. Implemented fast_rsa adapter in rsa_fast.dart:
   - RsaCryptoImpl wraps fast_rsa for all platforms
   - Converts fast_rsa.KeyPair to our platform-agnostic KeyPair
   - Maintains excellent performance (native code + WebAssembly)

3. Created singleton in rsa_impl.dart:
   - Provides single point of access via 'rsa' constant
   - Ready for platform-specific implementations if needed

4. Updated all consumers to use new types:
   - DpopCredentials now uses KeyPair instead of fast_rsa.KeyPair
   - SolidOidcUserManager adapted to new API
   - Removed genRsaKeyPair() helper (now rsa.generate())

BENEFITS:
- DPoP credentials can now be safely serialized and transferred to workers
- Clear separation between interface and implementation
- Preserves fast_rsa performance on all platforms
- No behavioral changes to existing functionality
- Simpler than initially anticipated - no need for web-specific implementation

KEY INSIGHT:
The abstraction isn't about replacing fast_rsa - it's about making the
*results* of fast_rsa operations portable across execution contexts by
using simple, serializable types (strings) instead of platform-specific
classes.
Architectural Improvements:
==========================

Split the library into two entry points to enable DPoP token generation
in Dart isolates and web workers without Flutter dependencies:

1. package:solid_auth/solid_auth.dart (Main entry point)
   - Full Flutter-enabled authentication library
   - SolidAuth class with UI integration
   - OIDC flow management with browser redirects
   - Session persistence using platform storage
   - Exports: SolidAuth, UserAndWebId, DpopCredentials, DPoP

2. package:solid_auth/worker.dart (Worker entry point - NEW)
   - Pure Dart, zero Flutter dependencies
   - Minimal API for DPoP token generation
   - Safe for use in isolates and web workers
   - Exports: DpopCredentials, DPoP, KeyPair

File Structure Changes:
======================

Moved/Created:
- lib/worker.dart (NEW) - Flutter-free public API
- lib/src/gen_dpop_token.dart (MOVED from solid_auth_client.dart)
- lib/src/oidc/dpop_credentials.dart (MOVED from solid_oidc_user_manager.dart)
- example/lib/dpop_worker_example.dart (MOVED from example/)

Deleted:
- lib/src/solid_auth_client.dart (split into gen_dpop_token.dart + imports)
- example/dpop_worker_example.dart (moved to example/lib/)

Modified:
- lib/src/oidc/solid_oidc_user_manager.dart
  - Removed DpopCredentials and DPoP classes (moved to dpop_credentials.dart)
  - Updated imports to use gen_dpop_token.dart
- lib/src/solid_auth.dart
  - Updated exports to reflect new file structure
- test/dpop_credentials_test.dart
  - Updated import to use new dpop_credentials.dart location

Benefits:
========

Performance:
- Offload cryptographic operations from main UI thread
- Generate multiple DPoP tokens in parallel
- Better responsiveness for high-throughput scenarios

Architecture:
- Clear separation of concerns (Flutter vs. pure Dart)
- Enables testing without Flutter test harness
- Potential reuse in non-Flutter Dart projects

Developer Experience:
- Explicit import paths prevent accidental Flutter deps in workers
- Comprehensive documentation in worker.dart
- Complete working examples

Documentation:
=============

Added comprehensive documentation covering:
- worker.dart: 90+ lines explaining architecture and usage
- gen_dpop_token.dart: RFC references and internal API docs
- README.md: Complete worker thread section with examples
- example/lib/dpop_worker_example.dart: Full working patterns

Security Model:
==============

Maintains existing security posture:
- Credentials safe for intra-process transfer only
- No persistent storage of serialized credentials
- Fresh token generation per request
- Private keys never leave credential objects

Testing:
=======

All existing tests pass:
- test/dpop_credentials_test.dart: 7/7 tests passing
- No behavioral changes to public API
- Example code analyzes without issues
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.

1 participant