Labels / Complexity: bug, auth, api, FrontEnd, Backend · Extremely High — 500
Problem
The cookie-based session flow is broken end-to-end. POST /api/auth/connect in quantara/web_app/api/auth.py sets an httpOnly cookie named wallet_id containing a session token:
response.set_cookie(key="wallet_id", value=session_token, httponly=True, secure=True, samesite="strict", max_age=..., path="/")
but no code path ever reads that cookie back. get_session in the same file takes wallet_id as a query parameter and 401s when it is absent:
async def get_session(request: Request, wallet_id: str | None = None):
# Note: Your REPO-002 auth middleware will automatically populate wallet_id from the cookie
if not wallet_id:
raise HTTPException(status_code=401, detail="No active wallet session")
return {"authenticated": True, "walletId": wallet_id}
There is no REPO-002 middleware, and session_store (quantara/web_app/api/session.py, which holds session:{token} -> wallet_id in Redis) is only ever written by create_session and deleted by delete_session; nothing calls session_store.get_wallet_id(token) to authenticate a request.
The frontend assumes the cookie works. initializeSession in quantara/frontend/src/stores/useWalletStore.js calls axios.get('/api/auth/session') with no query params and expects response.data.walletId. Because the backend requires the wallet_id query param, the request always 401s, and initializeSession always falls into its catch and sets walletId: null. Consequence: a returning user is never recognised from their cookie, the wallet must be reconnected on every load, and the session token in Redis is dead weight.
Root cause
# api/auth.py
async def get_session(request: Request, wallet_id: str | None = None):
if not wallet_id: # ← reads a query param, never request.cookies["wallet_id"]
raise HTTPException(status_code=401, detail="No active wallet session")
// stores/useWalletStore.js
const response = await axios.get('/api/auth/session'); // ← no query param, no cookie is sent/read
Why this is architecturally hard
- The fix must decide the authentication model: cookie-as-session (read
request.cookies["wallet_id"], look up session_store.get_wallet_id, and inject the wallet into the request) versus the existing header-signature flow (verify_wallet_signature in quantara/web_app/api/wallet_auth.py). Both exist today and are not reconciled.
- A cookie-session lookup needs a reusable FastAPI dependency or middleware so the rest of the API can actually authenticate from the cookie; this touches every endpoint's trust boundary, not just
/api/auth/session.
session_store is a module-level singleton in quantara/web_app/api/session.py, while wallet_auth.py uses an in-memory _nonce_store; reconciling the two session/credential stores is a prerequisite for a coherent fix.
- The frontend
initializeSession has no timeout/error differentiation, so any fix must also decide how the UI treats "no session" vs "network error" (currently both collapse to walletId: null).
Proposed design
A minimal coherent path:
@router.get("/session")
async def get_session(request: Request):
token = request.cookies.get("wallet_id")
wallet_id = await session_store.get_wallet_id(token) if token else None
if not wallet_id:
raise HTTPException(status_code=401, detail="No active wallet session")
return {"authenticated": True, "walletId": wallet_id}
plus a documented decision on whether the cookie or the signature header is authoritative for protected endpoints.
Downstream impact
/api/auth/session is the only endpoint whose contract changes, but if a cookie-session dependency is introduced, protected endpoints (quantara/web_app/api/position.py, vault.py, user.py) can adopt it. The frontend consumer is quantara/frontend/src/stores/useWalletStore.js.
Acceptance criteria
Service
Tests
Out of scope
Do not redesign wallet auth or migrate off the signature flow in this issue; only make the cookie session actually round-trip.
Getting started
Files in scope: quantara/web_app/api/auth.py, quantara/web_app/api/session.py, quantara/frontend/src/stores/useWalletStore.js. Verify with:
cd quantara && poetry run pytest web_app/tests -k session
cd quantara/frontend && yarn test:run
Good first files to read: quantara/web_app/api/auth.py, quantara/web_app/api/session.py, quantara/web_app/api/wallet_auth.py, quantara/frontend/src/stores/useWalletStore.js.
Labels / Complexity: bug, auth, api, FrontEnd, Backend · Extremely High — 500
Problem
The cookie-based session flow is broken end-to-end.
POST /api/auth/connectinquantara/web_app/api/auth.pysets an httpOnly cookie namedwallet_idcontaining a session token:but no code path ever reads that cookie back.
get_sessionin the same file takeswallet_idas a query parameter and 401s when it is absent:There is no
REPO-002middleware, andsession_store(quantara/web_app/api/session.py, which holdssession:{token} -> wallet_idin Redis) is only ever written bycreate_sessionand deleted bydelete_session; nothing callssession_store.get_wallet_id(token)to authenticate a request.The frontend assumes the cookie works.
initializeSessioninquantara/frontend/src/stores/useWalletStore.jscallsaxios.get('/api/auth/session')with no query params and expectsresponse.data.walletId. Because the backend requires thewallet_idquery param, the request always 401s, andinitializeSessionalways falls into itscatchand setswalletId: null. Consequence: a returning user is never recognised from their cookie, the wallet must be reconnected on every load, and the session token in Redis is dead weight.Root cause
Why this is architecturally hard
request.cookies["wallet_id"], look upsession_store.get_wallet_id, and inject the wallet into the request) versus the existing header-signature flow (verify_wallet_signatureinquantara/web_app/api/wallet_auth.py). Both exist today and are not reconciled./api/auth/session.session_storeis a module-level singleton inquantara/web_app/api/session.py, whilewallet_auth.pyuses an in-memory_nonce_store; reconciling the two session/credential stores is a prerequisite for a coherent fix.initializeSessionhas no timeout/error differentiation, so any fix must also decide how the UI treats "no session" vs "network error" (currently both collapse towalletId: null).Proposed design
A minimal coherent path:
plus a documented decision on whether the cookie or the signature header is authoritative for protected endpoints.
Downstream impact
/api/auth/sessionis the only endpoint whose contract changes, but if a cookie-session dependency is introduced, protected endpoints (quantara/web_app/api/position.py,vault.py,user.py) can adopt it. The frontend consumer isquantara/frontend/src/stores/useWalletStore.js.Acceptance criteria
Service
GET /api/auth/sessionauthenticates from the httpOnlywallet_idcookie viasession_storeand returns the storedwalletId.REPO-002comment is removed or replaced with the actual mechanism.Tests
initializeSessionreceiving and clearingwalletIdfrom the session response.cd quantara && poetry run pytest web_app/testsandcd quantara/frontend && yarn test:run.Out of scope
Do not redesign wallet auth or migrate off the signature flow in this issue; only make the cookie session actually round-trip.
Getting started
Files in scope:
quantara/web_app/api/auth.py,quantara/web_app/api/session.py,quantara/frontend/src/stores/useWalletStore.js. Verify with:Good first files to read:
quantara/web_app/api/auth.py,quantara/web_app/api/session.py,quantara/web_app/api/wallet_auth.py,quantara/frontend/src/stores/useWalletStore.js.