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>
98 lines
2.8 KiB
Plaintext
98 lines
2.8 KiB
Plaintext
# your domain, e.g https://example.com
|
|
APP_URL=http://localhost:3000
|
|
PORT=3000
|
|
|
|
# minimum of 32 characters. Generate one with: openssl rand -hex 32
|
|
APP_SECRET=REPLACE_WITH_LONG_SECRET
|
|
|
|
JWT_TOKEN_EXPIRES_IN=30d
|
|
|
|
DATABASE_URL="postgresql://postgres:password@localhost:5432/docmost?schema=public"
|
|
REDIS_URL=redis://127.0.0.1:6379
|
|
|
|
# options: local | s3 | azure
|
|
STORAGE_DRIVER=local
|
|
|
|
# S3 driver config
|
|
AWS_S3_ACCESS_KEY_ID=
|
|
AWS_S3_SECRET_ACCESS_KEY=
|
|
AWS_S3_REGION=
|
|
AWS_S3_BUCKET=
|
|
AWS_S3_ENDPOINT=
|
|
AWS_S3_FORCE_PATH_STYLE=
|
|
|
|
# Azure Blob Storage driver config
|
|
AZURE_STORAGE_ACCOUNT_NAME=
|
|
AZURE_STORAGE_ACCOUNT_KEY=
|
|
AZURE_STORAGE_CONTAINER=
|
|
|
|
# default: 50mb
|
|
FILE_UPLOAD_SIZE_LIMIT=
|
|
|
|
# options: smtp | postmark
|
|
MAIL_DRIVER=smtp
|
|
MAIL_FROM_ADDRESS=hello@example.com
|
|
MAIL_FROM_NAME=Docmost
|
|
|
|
# SMTP driver config
|
|
SMTP_HOST=127.0.0.1
|
|
SMTP_PORT=587
|
|
SMTP_USERNAME=
|
|
SMTP_PASSWORD=
|
|
SMTP_SECURE=false
|
|
SMTP_IGNORETLS=false
|
|
|
|
# Postmark driver config
|
|
POSTMARK_TOKEN=
|
|
|
|
# for custom drawio server
|
|
DRAWIO_URL=
|
|
|
|
# Gotenberg URL for server-side PDF export
|
|
GOTENBERG_URL=
|
|
|
|
DISABLE_TELEMETRY=false
|
|
|
|
# Allow other sites to embed Docmost in an iframe.
|
|
IFRAME_EMBED_ALLOWED=false
|
|
|
|
# Only used when IFRAME_EMBED_ALLOWED=true. When empty, any origin is allowed.
|
|
# Example: https://intranet.example.com,https://portal.example.com
|
|
IFRAME_ALLOWED_ORIGINS=
|
|
|
|
# Enable debug logging in production (default: false)
|
|
DEBUG_MODE=false
|
|
|
|
# Log database queries
|
|
DEBUG_DB=false
|
|
|
|
# Log http requests
|
|
LOG_HTTP=false
|
|
|
|
# MCP server (community): the embedded /mcp endpoint authenticates PER USER.
|
|
# An MCP client authenticates with one of:
|
|
# - HTTP Basic: `Authorization: Basic base64(email:password)` — the user's own
|
|
# Docmost login/password. The server validates the credentials and the MCP
|
|
# session then acts under that user's permissions (edits attributed to them).
|
|
# - Bearer access JWT: `Authorization: Bearer <access-jwt>` (the user's
|
|
# `authToken` cookie value). Validated as an ACCESS token.
|
|
#
|
|
# OPTIONAL service-account fallback. When a request carries NEITHER Basic NOR
|
|
# Bearer credentials and these are set, the MCP session falls back to this
|
|
# shared service account (back-compat; useful for CI/scripts). Leave BLANK to
|
|
# require per-user credentials.
|
|
MCP_DOCMOST_EMAIL=
|
|
MCP_DOCMOST_PASSWORD=
|
|
# MCP_DOCMOST_API_URL=http://127.0.0.1:3000/api
|
|
# Optional shared guard for the /mcp endpoint. When set, every /mcp request must
|
|
# carry a matching `X-MCP-Token` header (separate from `Authorization`, which now
|
|
# carries the per-user credentials). When unset, /mcp relies on the per-user
|
|
# credentials above plus the workspace MCP toggle and network isolation (do not
|
|
# expose the port publicly).
|
|
# MCP_TOKEN=
|
|
# MCP_SESSION_IDLE_MS=1800000
|
|
|
|
# Per-embedding-call timeout in milliseconds for the RAG indexer.
|
|
# A slow/hung embeddings endpoint fails after this and the batch continues.
|
|
# AI_EMBEDDING_TIMEOUT_MS=120000
|