API Client and Auth
API client
frontend/src/api/client.ts is the single file that all API calls go through. Every request to /v1/* is made here. This centralization means:
- Auth headers are added in one place
- Error handling is consistent
- Base URLs can be changed in one place for different environments
- TypeScript types from
frontend/src/api/types.tsare applied consistently
If you're adding a new API call, add a function to client.ts rather than writing fetch() directly in a page component.
Authentication flow
The frontend calls /v1/auth/login with email and password. The backend returns an access_token and refresh_token. These are stored in memory (or session storage) and sent as Authorization: Bearer <token> on every subsequent request.
// In client.ts (simplified)
const response = await fetch("/v1/auth/login", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ email, password }),
});
const { access_token } = await response.json();
The frontend uses frontend/src/auth/cognito.ts to authenticate directly with Cognito using SRP (Secure Remote Password) protocol. Cognito returns a Cognito access token (JWT). This JWT is then used as the Bearer token on backend requests.
The useAuth hook in frontend/src/hooks/useAuth.tsx abstracts this: the rest of the application calls useAuth() to get the current user and doesn't need to know which auth mode is active.
Token refresh
When the access token expires, the frontend automatically tries to refresh it:
- Local auth: calls
/v1/auth/refreshwith the refresh token - Cognito auth: uses Cognito's built-in token refresh mechanism
If refresh fails (e.g., the refresh token is also expired), the user is redirected to /login.
Debugging auth issues
401 on every request in the browser:
1. Open DevTools → Application → check what's stored for the access token
2. Verify the token isn't expired by decoding it at jwt.io
3. Call /v1/auth/me directly with the token to see if the backend accepts it:
curl -s http://localhost:8000/v1/auth/me \
-H "Authorization: Bearer <token-from-devtools>"
/v1/auth/me succeeds but page requests fail, check that client.ts is attaching the header correctly
Login works locally but fails in AWS:
- Confirm the frontend is configured with the correct Cognito user pool ID and app client ID
- Check the browser console for Cognito error messages
- Confirm VEGA_AUTH_PROVIDER=cognito is set in the API task definition
403 forbidden after login:
- The user is authenticated but lacks a required group in Cognito
- Check the user's group membership in the AWS Cognito console