Problem
Right now our app mixes multiple auth models (cookie session vs OAuth bearer tokens), but the URL surface area doesn’t make that obvious.
In particular, /api/* is currently used for the OAuth provider apiRoute (token-protected resource APIs), while our browser-facing JSON endpoints use cookie auth on non-/api paths (ex: /session, /auth, /logout, /chat-agent). This makes it hard to reason about what belongs in “the API”, what should be CSRF-protected, and which endpoints are intended for 3rd-party / token clients vs same-origin browser clients.
Current examples:
- OAuth protocol endpoints:
/oauth/authorize, /oauth/token, /oauth/register, /oauth/callback
- OAuth token resource endpoint:
GET /api/me (handled by OAuth provider apiRoute)
- Cookie/session endpoints:
/session, /auth, /logout, /password-reset/*, /chat-agent
- Docs mention
/api/chat, but code currently routes chat via /chat-agent
Goal
Make endpoint intent + auth requirements obvious from the path so we can:
- Avoid accidental CSRF exposure for cookie-auth JSON endpoints
- Avoid conflating OAuth protocol endpoints with resource APIs
- Set a clear convention for future endpoints (especially chat)
Proposed Solution
Adopt a consistent API namespace split:
/api/internal/* for same-origin, cookie-session-authenticated endpoints (CSRF-protected as needed)
/api/public/* for bearer-token-authenticated resource endpoints intended for non-browser / 3rd-party clients
Keep OAuth protocol endpoints under /oauth/* (authorize/token/register/callback).
Scope / Tasks
- Decide final routing + naming convention (this issue)
- Update worker routing so OAuth provider
apiRoute lives at /api/public/
- Move (or add) cookie-auth JSON endpoints under
/api/internal/
- Update any client fetches that should call internal endpoints
- Update docs that reference
/api/chat to match the chosen route (or implement /api/public/chat if that’s the intention)
- Add e2e + unit tests covering:
- internal endpoints require cookie session and are not accidentally bearer-authenticated
- public endpoints require bearer tokens and do not depend on cookies
Acceptance Criteria
- Every new endpoint clearly falls into either
/api/internal/* or /api/public/*
/api/public/* endpoints are bearer-only (no cookie session assumptions)
/api/internal/* endpoints are cookie-auth only (and have CSRF posture documented/tested)
- Documentation matches the implemented routes
References
worker/index.ts OAuthProvider is configured with apiRoute: '/api/' today
worker/oauth-handlers.ts implements GET /api/me
Problem
Right now our app mixes multiple auth models (cookie session vs OAuth bearer tokens), but the URL surface area doesn’t make that obvious.
In particular,
/api/*is currently used for the OAuth providerapiRoute(token-protected resource APIs), while our browser-facing JSON endpoints use cookie auth on non-/apipaths (ex:/session,/auth,/logout,/chat-agent). This makes it hard to reason about what belongs in “the API”, what should be CSRF-protected, and which endpoints are intended for 3rd-party / token clients vs same-origin browser clients.Current examples:
/oauth/authorize,/oauth/token,/oauth/register,/oauth/callbackGET /api/me(handled by OAuth providerapiRoute)/session,/auth,/logout,/password-reset/*,/chat-agent/api/chat, but code currently routes chat via/chat-agentGoal
Make endpoint intent + auth requirements obvious from the path so we can:
Proposed Solution
Adopt a consistent API namespace split:
/api/internal/*for same-origin, cookie-session-authenticated endpoints (CSRF-protected as needed)/api/public/*for bearer-token-authenticated resource endpoints intended for non-browser / 3rd-party clientsKeep OAuth protocol endpoints under
/oauth/*(authorize/token/register/callback).Scope / Tasks
apiRoutelives at/api/public//api/internal//api/chatto match the chosen route (or implement/api/public/chatif that’s the intention)Acceptance Criteria
/api/internal/*or/api/public/*/api/public/*endpoints are bearer-only (no cookie session assumptions)/api/internal/*endpoints are cookie-auth only (and have CSRF posture documented/tested)References
worker/index.tsOAuthProvider is configured withapiRoute: '/api/'todayworker/oauth-handlers.tsimplementsGET /api/me