Skip to content

mcpx: optional bearer token for /v1 and /mcp #1975

Closed

Description

@dezren39

Relocated from dezren39/darwin-nix#338 on 2026-10-28 (placement audit): mcpx's single source lives in developing-today/code (pkgs/mcpx); re-home tracked at #309. Original body below; issue references inside it are historical (dezren39/nix numbering).

Today anything that can reach the daemon's socket or loopback port is trusted; the Origin/Host check stops browsers, not callers.

Optional, off unless set: a setting (e.g. transport.bearerToken, from env so it need not live in a config file) that, when set, makes every /v1 and /mcp request carry Authorization: Bearer <token> or get 401. Unset keeps today's behaviour. Reject tokens shorter than 32 characters, as codex-connectors-mcp does.

The CLI, plugin and scripts read the same setting so they keep working. A first, cheap step toward #253 (authorization) and #300 (the permissive interface that authorizes everyone); principals per surface are #298.

Reference: https://github.com/wileai/codex-connectors-mcp (CODEX_CONNECTORS_HTTP_TOKEN).

Acceptance criteria

  • With transport.bearerToken set (sourced from env), every /v1 and /mcp request without a matching Authorization: Bearer <token> gets 401; with the token it succeeds.
  • With the setting unset, behaviour is byte-for-byte today's (no auth check).
  • Tokens shorter than 32 characters are rejected at startup/config load with a clear error.
  • The CLI, plugin, and scripts read the same setting and keep working when it is set.

Activity

  1. developing-today commented on Oct 28, 2026

    @developing-today
    Contributor
  2. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    History carried over from dezren39/darwin-nix#338 (verbatim, oldest first):


    @dezren39 · 2026-10-27T11:47:10Z

    Intake review

    Fleet monitor intake enrichment, 2026-10-27.

    Liveness: still live — no merged PR implements the optional bearer token. Related: #253 (OAuth authorization), #298 (principal per surface), #300 (permissive auth interface).

    Notes: Deliberately a first, cheap step — a shared secret, not principals. Suggested approach: single middleware check on both surfaces, one shared token-reading helper so CLI/plugin/scripts cannot drift.

    Risks: token comparison should be constant-time; do not log the token; docs must state this is not a substitute for #253/#298.

  3. added
    enhancementNew feature or request
    kind/securitySecurity issue or security hardening
    priority/normalOrdinary priority (the default)
    effort/mMedium: expected under 1 day of work
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 28, 2026
  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 29, 2026
  5. 46 remaining items

  6. dezren39 commented on Oct 30, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

  7. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · triaged → already implemented and on main; closing COMPLETED (the merge never auto-closed this issue)

    • Agent: queue worker repo-worker-code, OpenChamber scheduled lane (queue task 7806, coverage-pass triage)
    • Landed in: PR mcpx: optional bearer-token auth for /v1 and /mcp (#1975) #2711 — merged 2026-10-30T20:22:46Z as 85960a654807aecb42c431868f8baac0b4aa2e0b (branch queue/3271-1975-bearer-token), confirmed an ancestor of origin/main d3476bce7. Prior task 3271 logged the merge in its note; the issue itself stayed open because the PR carried no closing keyword.

    Acceptance criteria, verified at current main

    • ✅ Bearer enforced on every /v1 and /mcp request when set — internal/daemon/bearer.go:59 requireBearer wraps the whole HTTP surface, chained in both handler constructions (internal/daemon/server.go:457, :531); missing/mismatched credential → 401 with a message naming transport.bearerToken, constant-time compare.
    • ✅ Unset means today's behaviour — the wrapper is a pass-through when no token is configured (bearer.go reads transport.bearerToken, empty = no check).
    • ✅ Tokens under 32 characters rejected at config load with a clear error — MinBearerTokenLength check at bearer.go:50; internal/daemon/bearer_test.go:84 asserts the error names the setting and the 32-character minimum.
    • ✅ CLI, plugin and scripts read the same setting — internal/cli/client.go:134-193 (targetBearerToken, own-daemon and target-daemon resolution) plus docs/environment.md:112 for MCPX_TRANSPORT_BEARER_TOKEN handed to daemon-hosted scripts; internal/cli/bearer_test.go covers the eight previously-unauthorized CLI request paths and the target-daemon resolution P2.
    • Settings registry entry documented: docs/configuration.md:1070 (transport.bearerToken / --transport-bearer-token / MCPX_TRANSPORT_BEARER_TOKEN).

    Verification run for this triage (2026-11-03)

    • cd pkgs/mcpx && go test ./internal/daemon/ ./internal/cli/ -run Bearer -count=1 → ok / ok; the tree tested has zero diff against origin/main d3476bce7 in internal/daemon/bearer.go, internal/daemon/server.go and internal/cli.
    • Issue labels were already free of queue state; nothing in flight, no open PR, no competing branch.

    Scope note: this closes the optional bearer token step only. #253 (authorization), #298 (principals per surface) and #300 (permissive auth interface) remain the follow-on work and are untouched.

  8. added
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    on Nov 3, 2026
  9. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    state: triaged (coverage pass)
    Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as triage at priority 40 (priority/normal). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
    Found via: coverage pass 2026-11-03

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

Metadata

Metadata

Assignees

Labels

app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)effort/mMedium: expected under 1 day of workenhancementNew feature or requestkind/securitySecurity issue or security hardeningmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)queue/queuedHas a queued task in the Supabase agent queuesource/creatorFiled by the new-issue-creator jobstatus/needs-triageNot yet triaged; needs a first looktask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions