Skip to content

DRAFT - feat: add CAT/BAT (NUT-21/22) authentication support#92

Closed
4xvgal wants to merge 1 commit intocashubtc:masterfrom
4xvgal:feat/auth-wallet
Closed

DRAFT - feat: add CAT/BAT (NUT-21/22) authentication support#92
4xvgal wants to merge 1 commit intocashubtc:masterfrom
4xvgal:feat/auth-wallet

Conversation

@4xvgal
Copy link

@4xvgal 4xvgal commented Feb 10, 2026

Description

  • This PR adds NUT-21/22 authentication support (CAT/BAT) to CoCo, enabling OIDC-based mint authentication via
    mgr.auth.*. It integrates cashu-ts AuthManager which handles the full CAT/BAT lifecycle (CAT
    storage/refresh, BAT auto-minting/pool management, DLEQ validation, per-endpoint NUT-21 vs NUT-22 detection).

    The CAT flow is fully functional end-to-end. BAT (Blind Auth Token) flow requires multi-unit
    support (unit:'auth' keyset) which is tracked as future work. feat: add multi-unit support (sat, usd, auth, etc.) #88

    Key changes:

    • Added AuthApi class that orchestrates per-mint cashu-ts AuthManager + OIDCAuth lifecycle
    • Added AuthSession model, AuthSessionRepository interface, and MemoryAuthSessionRepository
    • Added AuthSessionService for session CRUD with expiration validation and event emission
    • Extended MintAdapter with setAuthProvider/clearAuthProvider to inject AuthProvider into cashu-ts Mint constructor
      (auto-includes CAT/BAT headers in all HTTP requests)
    • Exposed as mgr.auth following existing Service -> API -> Manager pattern
    • Added domain errors: AuthSessionError, AuthSessionExpiredError
    • Added events: auth-session:updated, auth-session:deleted, auth-session:expired

Notes to Reviewers

CAT Flow (working now): After mgr.auth.startDeviceAuth(mintUrl) or mgr.auth.login(mintUrl, tokens), the AuthProvider
is injected into MintAdapter. All subsequent Mint HTTP requests automatically include the Clear-auth header.
Session tokens are persisted via AuthSessionService and can be restored on app restart with
mgr.auth.restore(mintUrl).

BAT Flow (blocked): cashu-ts AuthManager handles BAT minting/pooling internally, but two things are
needed:

  1. Multi-unit support merged (unit:'auth' keyset) — currently a separate PR
  2. WalletService.buildWallet() needs to pass authProvider to its Mint instances

No Breaking Changes: All new APIs are additive. Existing code continues to work without modification.

No Database Migration Required: MemoryAuthSessionRepository is provided for tests. Platform storage adapters
(sqlite3, indexeddb, expo-sqlite) are tracked as future work.

API Changes

New: mgr.auth (AuthApi)

  • mgr.auth.startDeviceAuth(mintUrl) — OIDC Device Code Flow; returns { verification_uri, user_code, poll(), cancel()
    }
  • mgr.auth.login(mintUrl, tokens) — Manual login with externally obtained OIDC tokens
  • mgr.auth.restore(mintUrl) — Restore persisted session on app restart; returns boolean
  • mgr.auth.logout(mintUrl) — Delete session and disconnect AuthProvider
  • mgr.auth.getSession(mintUrl) — Get valid (non-expired) session; throws if missing/expired
  • mgr.auth.hasSession(mintUrl) — Check if session exists
  • mgr.auth.getAuthProvider(mintUrl) — Get cashu-ts AuthProvider for advanced use

New: MintAdapter

  • MintAdapter.setAuthProvider(mintUrl, provider) — Inject AuthProvider into Mint constructor
  • MintAdapter.clearAuthProvider(mintUrl) — Remove AuthProvider and invalidate cached Mint

New: AuthSessionService

  • AuthSessionService.saveSession(mintUrl, tokens) — Persist OIDC tokens as AuthSession
  • AuthSessionService.getValidSession(mintUrl) — Get session with expiration check
  • AuthSessionService.deleteSession(mintUrl) — Delete session
  • AuthSessionService.hasSession(mintUrl) — Check existence

Suggested CHANGELOG Updates

ADDED

  • AuthSession model — { mintUrl, accessToken, refreshToken?, expiresAt, scope? }
  • AuthSessionRepository interface — getSession, saveSession, deleteSession
  • MemoryAuthSessionRepository — In-memory implementation for tests
  • AuthApi class — NUT-21/22 authentication orchestrator (mgr.auth.*)
  • AuthApi.startDeviceAuth(mintUrl) — OIDC Device Code Flow
  • AuthApi.login(mintUrl, tokens) — Manual OIDC token login
  • AuthApi.restore(mintUrl) — Session recovery on app restart
  • AuthApi.logout(mintUrl) — Session cleanup
  • AuthApi.getSession(mintUrl) / hasSession(mintUrl) — Session queries
  • AuthApi.getAuthProvider(mintUrl) — Access cashu-ts AuthProvider
  • AuthSessionService — Session CRUD + expiration validation + event emission
  • AuthSessionError / AuthSessionExpiredError — Domain error classes
  • auth-session:updated / auth-session:deleted / auth-session:expired — EventBus events
  • MintAdapter.setAuthProvider() / clearAuthProvider() — AuthProvider injection
  • 9 unit tests for AuthApi
  • Integration test for OIDC Device Code Flow

MODIFIED

  • Manager — Added readonly auth: AuthApi, wired in buildCoreServices / buildApis
  • MintAdapter.getCashuMint() — Now passes authProvider to new Mint() constructor
  • RepositoriesBase — Added authSessionRepository field
  • AuthSessionService — Fixed Logger import (@nestjs/common → @core/logging)

Remaining Work (tracked in FEATURE_TODO.md)

  • Storage adapters: sqlite3, indexeddb, expo-sqlite
  • BAT persistence: AuthManager.exportPool() / importPool()
  • WalletService authProvider wiring (depends on multi-unit merge)
  • React wrapper hooks: useAuthSession(), useBatPool()

Test Coverage

Unit tests (9 new AuthApi tests, 441 total pass)
bun test packages/core/test/unit/AuthApi.test.ts

Integration test (requires mint with NUT-21/22 enabled + manual OIDC authorization)
MINT_URL=http://localhost:8085 bun test packages/core/test/integration/auth-session.test.ts --timeout 300000

I use customized oidc server nostr-oidc-ts for testing instead of KeyCloak
Which is pass cashu-ts AuthWallet device code flow test.

  authentication. Adds `mgr.auth.*` API following existing Service -> API
  -> Manager pattern.

New components:
  - AuthApi: orchestrates per-mint AuthManager + OIDCAuth lifecycle
    - startDeviceAuth(): OIDC Device Code Flow
    - login(): manual token injection
    - restore(): session recovery on app restart
    - logout(): cleanup session + AuthProvider
    - getSession() / hasSession() / getAuthProvider()
  - AuthSession model + AuthSessionRepository interface
  - AuthSessionService: session CRUD + expiration validation
  - MemoryAuthSessionRepository: in-memory impl for tests
  - MintAdapter: setAuthProvider/clearAuthProvider with cache invalidation
  - Domain errors: AuthSessionError, AuthSessionExpiredError
  - Events: auth-session:updated, auth-session:deleted, auth-session:expired

CAT flow is fully functional — AuthProvider is injected into Mint
  constructor.

BAT flow (NUT-22) requires multi-unit support (unit:'auth' keyset) and WalletService authProvider wiring - tracked as future work.

Tests: 9 unit tests (AuthApi) + integration test (Device Code FLow)
@changeset-bot
Copy link

changeset-bot bot commented Feb 10, 2026

⚠️ No Changeset found

Latest commit: 0d472bf

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@4xvgal 4xvgal changed the title feat: add CAT/BAT (NUT-21/22) authentication support DRAFT - feat: add CAT/BAT (NUT-21/22) authentication support Feb 10, 2026
@4xvgal 4xvgal closed this Feb 12, 2026
@github-project-automation github-project-automation bot moved this from Backlog to Done in coco Feb 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant