security(auth): consider binding Clerk azp in validateBearerToken
Why
server/auth-session.ts validateBearerToken verifies issuer, signature, expiry, and audience when present. It never reads azp. No caller does. Clerk sets azp to the origin that minted a browser session token and recommends checking it against authorized parties.
Probe on 2026-09-15 against api/internal/mcp-grant-mint.ts with the real resolveClerkSession, remote JWKS, and grant HMAC: a bearer with a foreign azp and a foreign Origin header mints a grant (200, one Redis write). Cookie-only, wrong-key, wrong-issuer, and expired tokens all return 401 with no write.
Why not now
Minting needs a JWT for the victim's sub. No origin that can obtain one has been shown. The only hosts under worldmonitor.app outside the app are clerk. (the identity provider) and abacus. (self-hosted Umami on our own infrastructure). Binding azp on one handler protects nothing that the gateway and Convex do not also accept.
If it is done
- Do it once in
validateBearerToken, not per handler. - Fail open when
azpis absent. Clerk omits it on non-browser tokens. - Survey what
azpdesktop (tauri://localhost), preview (worldmonitor-*-eliewm.vercel.app), and the subdomain hosts carry before choosing the allowlist. Seed it fromTRUSTED_RETURN_URL_ORIGINS.
Found during the 2026-09-15 security-validation batch (McpGrantMintOriginUnbound outcome, closed no-change).
Source: koala73/worldmonitor