Skip to content

Document MCP auth and transport plan for Prague and beyond. - #158

Open
bentumbler wants to merge 1 commit into
WLAN-Pi:devfrom
bentumbler:docs/mcp-auth-plan
Open

Document MCP auth and transport plan for Prague and beyond.#158
bentumbler wants to merge 1 commit into
WLAN-Pi:devfrom
bentumbler:docs/mcp-auth-plan

Conversation

@bentumbler

Copy link
Copy Markdown
Contributor

Summary

Defines how a user, an MCP client, wlanpi-mcp, and wlanpi-core authenticate to each other — a minimal-scope Prague slice that fixes the real risks (cleartext transport, non-working revocation, unenforced expiry), and a beyond-Prague target aligned with MCP spec 2026-07-28 (stateless Streamable HTTP, MCP as OAuth 2.1 resource server, no token passthrough).

Relationship to #139: stays exactly as scoped (credential-based dispatch + sentinel removal). It is item P1 here and the first dependency of everything else. This issue tracks the surrounding architecture.

Defects found during review (verified in code / on-device)

  1. The nginx: let JWT-bearing on-box clients reach the JWT auth path #135 premise is wrong: shared_secret.bin is root:wlanpi 0640 and wlanpi-mcp runs as User=wlanpi — MCP can read the HMAC secret today. Everything running as wlanpi is one trust class until permissions are tightened.
  2. Revocation doesn't reliably work: verify_token trusts the in-process cache without checking the revoked flag, and revoke_token never evicts it.
  3. JWT expiry is not enforced: time_validation_enabled = False; only the hourly DB purge retires tokens (~1h granularity).
  4. OTG stub is an auth-bypass landmine: if is_otg_request() ever returns True, verify_auth_wrapper returns with no authentication performed.
  5. The WebUI is an unauthenticated confused deputy (Appendix B of the doc): it reads core's HMAC secret and signs core API calls for any anonymous browser visitor — no login exists. Anonymous GET /startprofiler / /stopprofiler control services; /profiler/<filename> serves capture artifacts to anyone. TLS does not mitigate this. Arguably the largest currently-exploitable hole on the device.

Prague slice (P1–P8)

# Item
P1 #139: credential-based dispatch, remove nginx sentinel, remove OTG fall-through
P2 Fix revocation cache eviction; enable exp validation; TTL option (~24h interactive default)
P3 nginx TLS for core API + MCP with existing self-signed cert; UFW; dual-stack :31415 for one release (WLAN Pi app compat)
P4 Token hygiene: env/keychain on the client machine, getjwt --export/--write-env; no tokens in client configs
P5 MCP: drop X-Wlanpi-Client; classroom tool-allowlist profile
P6 Capture WS auth (#141) + did-owned stream handles + subscribe rights
P7 MCP capture tools using explicit handles
P8 Harness selection + student setup guide
P9 WebUI session login (PAM or device password) + CSRF/POST on mutating routes — closes defect 5
P10 CI guard rail: every core route must carry auth or be on an explicit public allowlist

Passthrough is kept for Prague as a documented, temporary deviation: on a single-owner box its marginal risk is negligible, and the budget goes to controls that stop actual classroom attacks. Session UX = daily-renewed JWT; continuity = ownership bound to did, not the token string.

Beyond-Prague (B1–B8, in the doc): Streamable HTTP, aud claims, core introspection endpoint (HS256 → no JWKS), MCP service identity plus signed did assertion (preserves per-user attribution), secret-permission tightening, pairing flow to replace SSH+getjwt (WLAN Pi app evolution), scopes. §5 of the doc shows this is non-breaking for the WLAN Pi app and getjwt if aud/scopes stay lenient — but it doubles Prague auth scope for no classroom risk reduction, hence the split. One cheap pull-forward: start issuing aud claims now, enforce later.

Decisions needed (please weigh in)

  1. WS subscribe policy (Appendix A): device-open reads for Prague (any valid token on the Pi may listen; only the owner stops/reconfigures) vs per-stream ACLs?
  2. WS handshake auth: first-message auth (recommended — keeps tokens out of URLs and nginx logs) vs Sec-WebSocket-Protocol?
  3. Revocation → force-close active WS listeners: Prague or beyond?
  4. TLS transition for the WLAN Pi app: dual-stack window length before cleartext :31415 is removed?
  5. Harness: which free/cost-effective MCP client for the classroom (gates P8 only)?
  6. Pull aud issuance forward? (recommended: yes)
  7. Is WebUI login (P9) Prague scope? (recommended: yes — defect 5 is exploitable today and MCP/TLS work doesn't touch it)
  8. WebUI login credential: PAM reuse (one credential story, same as SSH/Cockpit — recommended) vs dedicated device password?
  9. Public allowlist: should any core endpoint stay unauthenticated (e.g. minimal device-identity for discovery), or empty?

/cc @joshschmelzle @jsnyder81

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant