Files
AegisGitea-MCP/docs/adr/0004-auth-modes.md
T
Latte 8b7bb7205c docs: phase 0 audit, chunk plan, ADRs and pinned Gitea 28.1.0 swagger
Inventory and gap analysis of the 0.2.0 codebase against the full Gitea API
and the official gitea-mcp toolset, the B1..B11 + security chunk plan, ADRs
0001-0006 for the full-access rebuild, SDK/OAuth research notes, and the
instance swagger pinned for tool generation. The audit-logging doc moves to
docs/audit-logging.md.
2026-10-14 15:34:48 +02:00

2.0 KiB

ADR 0004: admin-token mode and per-user OAuth mode

Status: accepted (2026-10-14)

Context

Two authentication models must coexist on one deployment: an admin with full access, and other users who log in as themselves. Gitea is an OAuth2 provider but has no RFC 8414 metadata and no dynamic client registration; Mistral Le Chat requires dynamic client registration and Claude prefers it. Details: docs/research/sdk-oauth-gitea.md sections 4 and 6.

Decision

  • Admin-token mode (default). GITEA_TOKEN is used for every call. stdio always runs in this mode. On HTTP, a request carrying the static MCP_BEARER_TOKEN (constant-time comparison) runs in this mode.
  • Per-user OAuth mode (HTTP). The server is an OAuth 2.1 authorization server for MCP clients, using the SDK's OAuthAuthorizationServerProvider with dynamic client registration, and a confidential OAuth2 client of Gitea upstream (authorization code with PKCE S256, fixed and validated scope list). Our /oauth/callback exchanges the Gitea code, then issues our own opaque access and refresh tokens mapped to the user's Gitea tokens. Tool calls use the user's Gitea access token, so Gitea enforces that user's permissions; admin tools fail with Gitea's own 403 for non-admins. Upstream refresh is automatic.
  • Token store. A JSON file under DATA_DIR (default ~/.local/state/aegis-gitea-mcp, /var/lib/aegis-mcp in the image), mode 0600, values encrypted with Fernet using a key derived from TOKEN_ENCRYPTION_KEY. Our own tokens are stored only as SHA-256 hashes.
  • Combined verifier. One TokenVerifier accepts the static bearer (admin identity) or an issued OAuth token (user identity). The SDK requires passing it explicitly on the low-level server.
  • Identity in results. Every tool result carries identity: {login, mode, sudo}.

Consequences

The server holds per-user Gitea tokens. That is the most sensitive asset after the admin token and is covered by the threat model.