MedAssist uses HTTP-only cookies for browser sessions and also accepts Authorization: Bearer ... for JWT and API-key clients on authenticated API routes.
Session cookies are configured as:
httpOnly=true, so browser JavaScript cannot read token values.sameSite=lax, so cross-site subresource and form-style POST requests do not include session cookies in modern browsers.secure=truein production andsecure=falseonly for local development/test.
Authenticated state-changing routes are protected server-side by requireAuth. When authentication is enabled, these routes accept either a same-site session cookie, a valid Bearer JWT, or a write-scoped API key unless the route adds a stricter local check. Read-scoped API keys are rejected for mutation methods.
Cookie-auth state-changing route groups:
- Auth/session:
POST /auth/logout,PUT /auth/me,POST /auth/avatar,DELETE /auth/avatar,DELETE /auth/me - API keys:
POST /auth/api-keys,DELETE /auth/api-keys/:id - Medication data: medication create/update/delete, stock/refill/package actions, dose tracking, intake journal, refill history
- Settings and reminder tests:
PUT /settings,PUT /settings/language, test email/push endpoints, planner send/reminder endpoints - Export/import/report/share management: export request/import, report generation, share create/revoke/regenerate
- Medication enrichment: authenticated enrichment requests
Public token routes are not cookie-auth endpoints. Share links, share dose actions, and notification action tokens are authorized by their own opaque token values and must stay scoped to the token target.
GET /auth/state is intentionally public because the browser must know which login/setup UI to render before a user can authenticate. The response is limited to UX routing fields:
- whether authentication is enabled
- whether registration, form login, and OIDC login are available
- the configured OIDC provider display name
- whether first-user setup should be shown
The endpoint does not expose user records, usernames, provider issuer URLs, client IDs, secrets, token settings, or the raw user count. It is rate-limited and sends Cache-Control: no-store so browser setup state does not become stale after first-user registration.
Credentialed browser CORS is allowed only for configured CORS_ORIGINS. An unconfigured browser origin does not receive Access-Control-Allow-Origin, so the browser cannot grant credentialed cross-origin API access. Requests from unconfigured origins may still reach the backend outside browser CORS enforcement, so server-side authentication and authorization remain mandatory.
Public notification action routes allow arbitrary browser origins without credentials. This is intentional so external notification providers can send token-based actions without receiving browser session cookies.
/docs and /docs/json are enabled by default only outside production. Production deployments should leave OPENAPI_DOCS_ENABLED unset or set it to false unless interactive API docs are intentionally needed.
When docs are enabled while AUTH_ENABLED=true, DOCS_AUTH_REQUIRED defaults to true. If a deployment explicitly sets DOCS_AUTH_REQUIRED=false, only the documentation routes become public; protected API routes still require their normal cookie, Bearer JWT, or API-key authentication.
No additional CSRF token is required for the current browser contract because state-changing session requests rely on SameSite=Lax, credentialed CORS allowlists, JSON/fetch-based clients, server-side auth, and current-password checks for sensitive account changes.
Add explicit CSRF-token protection before allowing any of these changes:
SameSite=Nonecookies or third-party embedding.- Simple cross-site form submissions for state-changing routes.
- New high-risk cookie-auth mutations that do not require JSON/fetch preflight or a separate confirmation factor.
- Broadening credentialed CORS beyond trusted application origins.