The endurance test refuted the sliding-window model I committed earlier. A keepalive doing only GET /api/v3/me succeeded at t+0/30/60/90 and was still rejected by t+120 — consistent with the session ending ~2h after LOGIN (t+107), and inconsistent with 2h after the last request, which would have been t+210. This is a live-vs-source divergence, not a misreading: both the current JwtWhitelistAdapter and the legacy Feathers ensureTokenIsWhitelisted re-set the Valkey TTL on every authenticated request, so the source reads as a sliding window. The instance does not behave that way. So the keepalive now calls POST /authentication/refresh-session, the endpoint behind the UI's "Sitzung verlängern" button, which a separate 100s test showed does hold the reported budget at 7200s. It is the only non-GET request in the server: no body, touches only our own session, cannot read or modify user data, and is not exposed as a tool, so no model-driven call can ever be a POST. It logs the returned budget, which makes a failing extension visible before the session is lost. Whether this is sufficient is NOT established. Two mechanisms still fit: an idle TTL that reads fail to refresh (keepalive works), or an absolute cap/revocation anchored at login — e.g. the IDP's back-channel logout, which clears every token for the account rather than one. Added scripts/session-diagnose.mjs to settle it: it logs the budget every 10 min, so a decaying series indicates the former and an abrupt 401 at 7200s the latter. Docs state the open question rather than asserting a mechanism. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
46 lines
1.9 KiB
Plaintext
46 lines
1.9 KiB
Plaintext
# ---------------------------------------------------------------------------
|
|
# Schulcloud instance
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Base URL of the instance, no trailing slash.
|
|
TSC_URL=https://schulcloud-thueringen.de
|
|
|
|
# The value of the `jwt` cookie from a logged-in browser session.
|
|
# The 30-day `exp` in the token is NOT its lifetime: sessions have been measured
|
|
# ending ~2h after login, and ordinary API reads do not extend them. The
|
|
# keepalive calls refresh-session to try to hold it. See docs/AUTH.md.
|
|
TSC_JWT_COOKIE=
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# This MCP server
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Shared secret callers must present as `Authorization: Bearer <token>`.
|
|
# REQUIRED for the public deployment — without it the endpoint is open to
|
|
# anyone who finds the hostname. Generate one with:
|
|
# openssl rand -hex 32
|
|
MCP_AUTH_TOKEN=
|
|
|
|
# Listen address inside the container. Leave as-is when running behind Caddy.
|
|
PORT=8080
|
|
BIND_HOST=0.0.0.0
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Limits (optional — sensible defaults are built in)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Largest file download_file will pull, in bytes. Default 25 MiB.
|
|
# Videos in Schulcloud routinely exceed this; they are not extractable anyway.
|
|
# MAX_DOWNLOAD_BYTES=26214400
|
|
|
|
# Characters of extracted text returned before truncation. Default 120000.
|
|
# MAX_EXTRACTED_CHARS=120000
|
|
|
|
# Per-request timeout against the Schulcloud API, in ms. Default 30000.
|
|
# REQUEST_TIMEOUT_MS=30000
|
|
|
|
# How often to call refresh-session to hold the session open, in ms. Default
|
|
# 1800000 (30 min). Must stay well under the instance's JWT_TIMEOUT_SECONDS —
|
|
# 7200s here, readable from GET /api/v3/config/public. Set to 0 to disable.
|
|
# KEEPALIVE_INTERVAL_MS=1800000
|