Skip to content

feat: authenticate with a scoped API key (FIP-07), connect once#3

Open
islandbitcoin wants to merge 1 commit into
mainfrom
feat/fip07-api-key-auth
Open

feat: authenticate with a scoped API key (FIP-07), connect once#3
islandbitcoin wants to merge 1 commit into
mainfrom
feat/fip07-api-key-auth

Conversation

@islandbitcoin

Copy link
Copy Markdown
Contributor

What

After OTP login, the mod now mints a scoped Flash API key (FIP-07), stores it, and authenticates every request with X-API-KEY — so returning users skip captcha/OTP (connect once). Logout revokes the key.

Chosen model: OTP bootstraps login → auto-mint a least-privilege key → persist in localStorage → reuse across reopens.

Why

Today the session token lives in sessionStorage (tab-scoped), so users re-run captcha + OTP every time they reopen the mod inside the Fedi webview. A scoped, revocable, expiring API key gives a durable connection without holding a full session.

Changes

  • flash/client.ts — prefer X-API-KEY, fall back to Bearer (used to bootstrap login + mint); localStorage-backed key store; a 401 clears both credentials.
  • flash/operations.tscreateApiKey() + revokeApiKey(id).
  • state/FlashContext.tsx — mint-on-login (best-effort: if minting fails, login still works on the session token); Logout revokes + clears.
  • config.ts / types.ts — key config (scopes, 30-day expiry, name) + types.
  • vite.config.ts — dev/preview proxy now targets api.test.flashapp.me (the feature is on TEST first; override via VITE_FLASH_PROXY_TARGET).
  • docs.env.example + README updated (incl. correcting the old "never localStorage" note).

Scopes requested: read_user, read_wallet, read_transactions, write_wallet, write_transactions — no admin, no write_user.

Verification

End-to-end against Flash TEST (app-review account): userLoginapiKeyCreate (returns id, correct scopes) → me via X-API-KEYapiKeyRevoke(id) → revoked key rejected with 401. No keys left active.

  • ✅ 78 unit tests (+10 new: X-API-KEY preference, 401-clears-both, mint-on-login, mint-failure fallback, revoke-on-logout, mutation shape/scopes/expiresIn)
  • tsc --noEmit + vite build

Notes

  • The static build talks to Flash directly; a deployed origin still needs to be on Flash's TEST CORS allowlist (the vite proxy only covers local dev/preview).
  • API-key names are restricted to letters / numbers / spaces / hyphens / underscores (discovered during verification; "Flash FediMod" is valid).

🤖 Generated with Claude Code

After OTP login the mod mints a scoped Flash API key (read_user/read_wallet/
read_transactions + write_wallet/write_transactions, 30-day expiry), persists it
in localStorage, and authenticates every request with X-API-KEY. Returning users
skip captcha/OTP; Logout revokes the key.

The GraphQL client prefers X-API-KEY and falls back to the session Bearer token
(used to bootstrap login and mint the key). A 401 clears both credentials.
Minting is best-effort: if the endpoint lacks the feature, login still works on
the session token.

The feature is live on Flash TEST first, so the dev/preview proxy now targets
api.test.flashapp.me (override via VITE_FLASH_PROXY_TARGET).

Verified end-to-end against TEST: login -> apiKeyCreate -> me via X-API-KEY ->
apiKeyRevoke -> revoked key rejected (401). 78 unit tests pass (+10), typecheck
and production build clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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