The embedded MCP server acted as a single service account; now each /mcp
session authenticates as the current user, so tools run under that user's
CASL and edits attribute to them.
- HTTP Basic (chosen path): Authorization: Basic email:password, validated
server-side via AuthService; the session carries the issued user JWT (not
the raw password). Password may contain ':' (split on first only).
- Bearer fallback: Authorization: Bearer <access JWT>, verified as ACCESS and
additionally checked for an active session + non-disabled user (matching
JwtStrategy), so revoked/disabled users are rejected.
- Service account stays as an optional fallback (no creds + env configured).
- packages/mcp createMcpHttpHandler accepts a per-request config resolver
(back-compat: static config / stdio unchanged); identity is bound to the
mcp-session-id at init and re-validated from the caller's own credentials on
every request (anti session-fixation: a guessed session id can't be reused
without matching creds).
- A full login (session + audit) happens only once at session init; later
requests re-verify credentials via a new non-side-effecting
AuthService.verifyUserCredentials (no session/audit spam).
- Failed-login limiter (5/60s, keyed per-IP, per-IP+email, and per-email so IP
rotation can't brute one account) since direct login bypasses the controller
throttler. Only real credential failures count.
- MCP_TOKEN shared guard moved off Authorization to an X-MCP-Token header
(timing-safe compare); credsConfigured 503 gate replaced by a clear 401.
- No secrets logged; all auth resolved before res.hijack() so failures return
clean 401 JSON. .env.example marks the service account optional.
Implements docs/backlog/mcp-per-user-auth.md (variant L).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* stripe init
git submodules for enterprise modules
* * Cloud billing UI - WIP
* Proxy websockets in dev mode
* Separate workspace login and creation for cloud
* Other fixes
* feat: billing (cloud)
* * add domain service
* prepare links from workspace hostname
* WIP
* Add exchange token generation
* Validate JWT token type during verification
* domain service
* add SkipTransform decorator
* * updates (server)
* add new packages
* new sso migration file
* WIP
* Fix hostname generation
* WIP
* WIP
* Reduce input error font-size
* set max password length
* jwt package
* license page - WIP
* * License management UI
* Move license key store to db
* add reflector
* SSO enforcement
* * Add default plan
* Add usePlan hook
* * Fix auth container margin in mobile
* Redirect login and home to select page in cloud
* update .gitignore
* Default to yearly
* * Trial messaging
* Handle ended trials
* Don't set to readonly on collab disconnect (Cloud)
* Refine trial (UI)
* Fix bug caused by using jotai optics atom in AppHeader component
* configurable database maximum pool
* Close SSO form on save
* wip
* sync
* Only show sign-in in cloud
* exclude base api part from workspaceId check
* close db connection beforeApplicationShutdown
* Add health/live endpoint
* clear cookie on hostname change
* reset currentUser atom
* Change text
* return 401 if workspace does not match
* feat: show user workspace list in cloud login page
* sync
* Add home path
* Prefetch to speed up queries
* * Add robots.txt
* Disallow login and forgot password routes
* wildcard user-agent
* Fix space query cache
* fix
* fix
* use space uuid for recent pages
* prefetch billing plans
* enhance license page
* sync