useAuth reports authentication from cookie presence and fabricates userAddress: client auth state is a mock
Labels / Complexity: bug · security · Medium Complexity — Medium
Problem
The shared useAuth hook (useAuth.ts) derives authentication state from the mere presence of a cookie and returns a fabricated address. The relevant block:
const hasToken = document.cookie.includes('auth-token=');
// Mocking check - in production, validate JWT or wallet state here
setAuthState({
isAuthenticated: hasToken,
isLoading: false,
userAddress: hasToken ? '0x...' : null, // Get from wallet provider
});
So with any cookie whose name contains auth-token= (including an expired, invalid, or forged value), useAuth reports isAuthenticated: true and userAddress: '0x...' — a literal placeholder string, not the user's address. The server-side middleware.ts now validates the JWT (closed #652), but this client hook bypasses that validation entirely and will happily render authenticated UI for a garbage cookie. Consequences:
- UI trusts a string match. Components gating on
isAuthenticated (dashboard, portfolio, settings) show authenticated views for any cookie name match, regardless of signature or expiry.
userAddress: '0x...' is a hardcoded fake. Anything that reads userAddress (transaction displays, profile headers, address-bound calls) displays and may use the placeholder address in place of the connected wallet's real address.
- The hook and the middleware disagree about what "authenticated" means, so auth state is inconsistent between the server-side gate and the client UI.
Root cause
useAuth.ts lines ~25-33: document.cookie.includes('auth-token=') as the sole auth signal and '0x...' as the address. The comment ("Mocking check - in production, validate JWT or wallet state here") documents that this is unfinished.
Why this is architecturally hard
- Client-side JWT validation is not the same as the middleware's.
useAuth runs in the browser; verifying the JWT there would require shipping the secret (impossible) or relying on a verification endpoint. The realistic design is a session/me endpoint on PropChain-BackEnd (the backend has sessions and users modules) or aligning with the wallet layer via useWalletConnector — the contributor must pick the source of truth and mirror it in useAuth.
- The address source is a separate problem. The hook currently fakes
userAddress; the real value belongs to either the wallet provider (useWalletConnector/walletStore.ts) or the backend session. The fix must decide which and stop the hook from inventing one.
- Consumers depend on the current shape. Components read
isAuthenticated, isLoading, userAddress; changing what sets them (or adding an error/unverified state) is a small API change that must be coordinated with AuthGuard.tsx and the components that consume the hook, with tests updated.
Downstream impact
Frontend-only; no contract or backend change. If a session-verification endpoint is chosen as the source of truth, coordinate the endpoint contract with PropChain-BackEnd's sessions module.
Acceptance criteria
useAuth no longer treats document.cookie.includes('auth-token=') as authentication; an expired/invalid/forged token results in isAuthenticated: false.
userAddress is never the literal '0x...' placeholder; it comes from the wallet provider or a verified session, or is null when unknown.
- The "Mocking check" comment is gone.
- Tests cover: no cookie -> unauthenticated; cookie present but unverified/expired -> unauthenticated; verified session or connected wallet -> authenticated with the real address.
npm run typecheck, npm test, and npm run lint pass.
Out of scope
Redesigning the backend session API and moving PROTECTED_ROUTES handling are out of scope; this issue is about the client hook's state derivation.
Getting started
useAuth.ts — the mock block (lines ~25-33)
useWalletConnector.ts / src/store/walletStore.ts — the wallet address source to use instead of '0x...'
AuthGuard.tsx — a consumer that gates on this hook's state
Commands: npm run typecheck, npm test, npm run lint.
Good first files to read: useAuth.ts, useWalletConnector.ts, AuthGuard.tsx.
useAuth reports authentication from cookie presence and fabricates userAddress: client auth state is a mock
Labels / Complexity: bug · security · Medium Complexity — Medium
Problem
The shared
useAuthhook (useAuth.ts) derives authentication state from the mere presence of a cookie and returns a fabricated address. The relevant block:So with any cookie whose name contains
auth-token=(including an expired, invalid, or forged value),useAuthreportsisAuthenticated: trueanduserAddress: '0x...'— a literal placeholder string, not the user's address. The server-sidemiddleware.tsnow validates the JWT (closed #652), but this client hook bypasses that validation entirely and will happily render authenticated UI for a garbage cookie. Consequences:isAuthenticated(dashboard, portfolio, settings) show authenticated views for any cookie name match, regardless of signature or expiry.userAddress: '0x...'is a hardcoded fake. Anything that readsuserAddress(transaction displays, profile headers, address-bound calls) displays and may use the placeholder address in place of the connected wallet's real address.Root cause
useAuth.tslines ~25-33:document.cookie.includes('auth-token=')as the sole auth signal and'0x...'as the address. The comment ("Mocking check - in production, validate JWT or wallet state here") documents that this is unfinished.Why this is architecturally hard
useAuthruns in the browser; verifying the JWT there would require shipping the secret (impossible) or relying on a verification endpoint. The realistic design is a session/me endpoint onPropChain-BackEnd(the backend hassessionsandusersmodules) or aligning with the wallet layer viauseWalletConnector— the contributor must pick the source of truth and mirror it inuseAuth.userAddress; the real value belongs to either the wallet provider (useWalletConnector/walletStore.ts) or the backend session. The fix must decide which and stop the hook from inventing one.isAuthenticated,isLoading,userAddress; changing what sets them (or adding anerror/unverifiedstate) is a small API change that must be coordinated withAuthGuard.tsxand the components that consume the hook, with tests updated.Downstream impact
Frontend-only; no contract or backend change. If a session-verification endpoint is chosen as the source of truth, coordinate the endpoint contract with
PropChain-BackEnd'ssessionsmodule.Acceptance criteria
useAuthno longer treatsdocument.cookie.includes('auth-token=')as authentication; an expired/invalid/forged token results inisAuthenticated: false.userAddressis never the literal'0x...'placeholder; it comes from the wallet provider or a verified session, or isnullwhen unknown.npm run typecheck,npm test, andnpm run lintpass.Out of scope
Redesigning the backend session API and moving
PROTECTED_ROUTEShandling are out of scope; this issue is about the client hook's state derivation.Getting started
useAuth.ts— the mock block (lines ~25-33)useWalletConnector.ts/src/store/walletStore.ts— the wallet address source to use instead of'0x...'AuthGuard.tsx— a consumer that gates on this hook's stateCommands:
npm run typecheck,npm test,npm run lint.Good first files to read:
useAuth.ts,useWalletConnector.ts,AuthGuard.tsx.