Skip to content

fix(#712/#711/#710/#709): wire auth tokens, mock IDs, limits API, set… - #747

Merged
Jambox11 merged 1 commit into
mux-labs:stagingfrom
yahia008:feat/fix-712-711-710-709
Aug 31, 2026
Merged

fix(#712/#711/#710/#709): wire auth tokens, mock IDs, limits API, set…#747
Jambox11 merged 1 commit into
mux-labs:stagingfrom
yahia008:feat/fix-712-711-710-709

Conversation

@yahia008

Copy link
Copy Markdown

Title: fix: wire auth tokens, mock IDs, limits API, and settings backend
(#712/#711/#710/#709)

──────────────────────────────────────────────────────────────────────────────────

Description:

Closes #712
Closes #711
Closes #710
Closes #709

Summary

Four related gaps that caused the dashboard to serve mock data, unauthenticated
requests, and local-only state in production.

──────────────────────────────────────────────────────────────────────────────────

#712 — Login must store tokens required by wallet routes

POST /api/auth/login only wrote the backend's session token to the HttpOnly cookie
— no token block was returned to the client. useWallets and other client fetches
rely on Authorization: Bearer from sessionStorage, so they were hitting
the wallets route unauthenticated and getting 401s.

Fix: when the backend returns a token, the login route now synthesises a session
block in the JSON response alongside the HttpOnly cookie. AuthContext.signIn
already persisted it to sessionStorage; now it has something to persist.

──────────────────────────────────────────────────────────────────────────────────

#711 — Wallet detail page must not depend on Storybook mock IDs

Stories used hardcoded ID strings ("wallet-001", etc.) that had to stay in sync
with src/mock-data/wallets.ts by convention.

Fix: MOCK_WALLET_IDS constants exported from src/mock-data/wallets.ts.
WalletDetail.stories.tsx now imports them — a rename or addition propagates from
one place. Tests verify every constant resolves to a real dummyWallets entry with
the correct network/status.

──────────────────────────────────────────────────────────────────────────────────

#710 — Spending limits must use Limits API, not local store

SpendingLimitsCard called fetch("/api/spending-limits") without an Authorization
header. The route also had no auth gate and no explicit production/mock split.

Fix: SpendingLimitsCard now reads the bearer token from sessionStorage and
attaches it on all GET and PUT requests. The route requires a Bearer token (401
otherwise), returns mock defaults in dev/CI, and returns 503 backend_unavailable
in production with no backend.

──────────────────────────────────────────────────────────────────────────────────

#709 — Settings page must persist to backend

The settings page read and wrote preferences from localStorage — changes were
browser-local, not persisted to any account, and silently lost if localStorage was
cleared.

Fix: new GET/PATCH /api/settings route proxies to
MUX_BACKEND_URL/developers/me/settings, requires Bearer auth, echoes a mock
payload in dev, and returns 503 in production with no backend. Settings page is
rewritten to load on mount and save on submit via the API; localStorage is no
longer touched.

──────────────────────────────────────────────────────────────────────────────────

Tests

  • src/app/api/auth/login/route.test.ts — session block echo in mock and
    real-backend paths
  • src/mock-data/wallets.test.ts — every MOCK_WALLET_IDS constant resolves to a
    matching dummyWallets entry
  • src/app/api/spending-limits/route.test.ts — auth gating, production mock guard,
    and proxy behavior (preserves original coverage)
  • src/app/api/settings/route.test.ts — auth gating, validation, mock echo,
    production 503, and proxy for both GET and PATCH
  • src/app/dashboard/settings/page.test.tsx — rewritten: API-backed load/save,
    Authorization header sent, no localStorage writes
  • src/components/dashboard/tests/SpendingLimitsCard.test.tsx — new test
    verifying Authorization header is sent; existing assertions updated to
    objectContaining

Production/mock split

All four routes follow the same pattern as the rest of the app: mock fallback
allowed outside production, explicit 503 backend_unavailable in production with no
backend configured. No new default secrets. No credentials in NEXT_PUBLIC_* or
localStorage.

…okens, mock IDs, limits API, settings backend

mux-labs#712 — login route now echoes a session block in its JSON response when the
backend returns a token, so the client can persist it to sessionStorage and
attach Authorization: Bearer on wallet/API requests. Previously only the
HttpOnly cookie was set server-side; client fetches went out unauthenticated.

mux-labs#711 — export MOCK_WALLET_IDS constants from src/mock-data/wallets.ts.
WalletDetail.stories.tsx now references those constants instead of hardcoded
strings, so a mock ID rename propagates from one place and stories never
silently load a NotFound state.

mux-labs#710 — SpendingLimitsCard now passes Authorization: Bearer on every fetch to
/api/spending-limits. The route itself now requires a Bearer token (401
otherwise) and has an explicit isMockFallbackAllowed() guard: default limits
are returned in dev/CI, 503 backend_unavailable in production with no backend.

mux-labs#709 — new /api/settings route (GET + PATCH) proxies to
MUX_BACKEND_URL/developers/me/settings, requires Bearer auth, returns a mock
echo in dev and 503 in production with no backend. Settings page is rewritten
to load from and save to /api/settings instead of localStorage; no project
preferences ever touch the browser store.
@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@yahia008 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

@Jambox11
Jambox11 merged commit c1cbc84 into mux-labs:staging Aug 31, 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

2 participants