A production-grade mobile authenticator for TOTP/HOTP built with Flutter.
This app stores and generates one-time passwords (TOTP/HOTP) locally, supports QR scanning, secure encrypted storage, biometric unlocking, and export/import of accounts.
- Add accounts via QR code (otpauth://) or manual entry
- Generate TOTP/HOTP codes continuously and copy them with one tap
- Securely persist secrets using platform secure storage (OS-level)
- Optional biometric/device-credential gating for unlocking
- Export and import accounts (encrypted backup)
- Scan QR codes to add accounts with
mobile_scanner
- OTP generation: core TOTPs handled in
core/utils/totp_engine.dartand theotppackage - Secure storage: secrets stored with
flutter_secure_storageviacore/security/secure_storage_service.dart - Local database: metadata persisted with Drift (SQLite) (
core/database/app_database.dart) - Biometric auth:
local_authwith a RiverpodAppLockprovider for gating - State management: Riverpod + code generation (
riverpod_annotation,riverpod_generator) - Navigation:
go_router - QR scanning:
mobile_scanner - Code generation:
build_runner,freezed,json_serializable,drift_dev
lib/
├── main.dart
├── app/
│ ├── app.dart
│ └── router.dart
├── core/
│ ├── constants/
│ ├── database/
│ ├── security/
│ ├── theme/
│ └── utils/
├── features/
│ ├── auth/ # Sign-in, onboarding, biometric providers
│ ├── presentation/
│ └── providers/
├── auth_tokens/ # Tokens domain: data, domain, presentation
├── export_import/ # Backup and restore services
├── scanner/ # QR scanning UI
└── settings/ # App settings and preferences
└── assets/
Key files:
- Provider implementing app lock: lib/features/auth/presentation/providers/biometric_provider.dart
- Secure storage wrapper: lib/core/security/secure_storage_service.dart
- TOTP helper/parser: lib/core/utils/totp_engine.dart and lib/core/utils/otp_uri_parser.dart
Requirements:
- Flutter SDK (matching the project's
environment.sdk— Dart >= 3.8.0) - Android SDK (for Android builds) or Xcode (for iOS builds)
Install deps and generate code:
flutter pub get
dart run build_runner build --delete-conflicting-outputsRun on a connected device or emulator:
flutter run
# specify device: flutter run -d emulator-5554Build release artifacts:
# Android APK
flutter build apk --release
# iOS (requires Xcode/macOS and proper signing)
flutter build ipa --releaseIf you see No Android SDK found, export ANDROID_HOME or install the Android SDK and set up the platform tools. See Android setup in Flutter docs.
- Code generation is used for Riverpod providers, freezed models, and Drift migrations. Re-run the build runner after changing annotated files.
- Tests:
flutter test - Linting:
flutter analyze - If you encounter issues after dependency upgrades, run
flutter cleanand rebuild.
| Property | Mechanism |
|---|---|
| Confidentiality | Secrets stored encrypted via flutter_secure_storage (OS keystore/enclave) |
| Integrity | TOTP/HOTP algorithm and app metadata validated locally |
| Biometric gating | local_auth + Riverpod AppLock for optional biometric/device credential unlocking |
| Offline-first | All secrets and code generation happen locally; no secret-sharing to servers |
Limitations: endpoint compromise or device compromise can expose secrets. Always back up your encrypted export and keep your device secure.
- Build error
No Android SDK found: ensureANDROID_HOMEorANDROID_SDK_ROOTis set and Android command-line tools are installed. - If
local_author biometrics behave differently across OS versions, check plugin docs and platform setup (Android permissions, iOS entitlements). - Codegen mismatches: run
dart run build_runner build --delete-conflicting-outputs.
MIT