decocms / decocms/studio

Warp tunnel: verify OAuth access tokens so 'decocms link' can use per-user auth

Open
#3,284 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
407
Forks
57
Avg merge
5h 6m
Merged PRs (30d)
880

Description

Background

bunx decocms link (added in #3282, fixed in #3283) opens a tunnel through the Warp server (@deco-cx/warp-node). Today the tunnel is authenticated with a hardcoded shared key (DECO_TUNNEL_SERVER_TOKEN, with a fallback constant in the CLI source) — every CLI install uses the same secret.

PR #3282 pivoted the CLI auth flow to standard OAuth 2.1 + PKCE against Better Auth's MCP plugin, which means each user now has their own access token in ~/.deco/session.json. The CLI was originally wired to send that access token as the Warp apiKey, but the Warp server doesn't know how to verify it — it dropped the registration silently and the CLI hung indefinitely. PR #3283 reverted to the shared key as a stop-gap.

Goal

Update the Warp tunnel server so it accepts the user's OAuth access token (or an equivalent per-user credential) for the register handshake, and rejects requests that don't carry a valid one.

What to do

  1. On the Warp server side:

    • Accept an OAuth bearer token in the existing apiKey field of the register message (or read from a new Authorization header — TBD which is cleaner).
    • Validate the token against the decocms auth server (introspect via JWT signature + issuer, or hit a verification endpoint).
    • Reject (with an explicit error message) registrations whose token is missing, expired, or invalid — currently rejection is silent.
    • Optionally: bind the requested subdomain to the token's `sub` so a user can only register subdomains derived from their own identity.
  2. On the CLI side (one-line change once Warp is ready):

    • Flip defaultTunnelOpener in apps/mesh/src/cli/commands/link.ts from:
      ```ts
      apiKey: process.env.DECO_TUNNEL_SERVER_TOKEN ?? LEGACY_TUNNEL_TOKEN,
      ```
      back to:
      ```ts
      apiKey: params.apiKey,
      ```
    • Remove the LEGACY_TUNNEL_TOKEN constant.
    • The 15s registration timeout (also added in #3283) acts as a safety net during the cutover so a misconfigured client surfaces an error rather than hanging.
  3. Token refresh (nice-to-have, not strictly blocking):

    • The CLI session already persists refreshToken and expiresAt from the OAuth response. Add transparent refresh in the CLI (or document that users re-run `auth login` on expiry) so long-running tunnels survive token rotation.

References

  • PR #3282 — original CLI feature + OAuth pivot (merged, shipped as decocms@2.304.0)
  • PR #3283 — temporary revert to legacy shared key + 15s registration timeout
  • `apps/mesh/src/cli/commands/link.ts` — defaultTunnelOpener
  • `apps/mesh/src/auth/index.ts` — Better Auth MCP plugin config (already exposes /api/auth/mcp/register, /authorize, /token)
  • Warp client code: `@deco-cx/warp-node` (Connected.registered never resolves on silent rejection — that's the silent-hang failure mode #3283 papers over)

Acceptance

  • A decocms link running against a Warp server that has been updated to verify OAuth tokens succeeds end-to-end without the legacy shared key.
  • An invalid or missing token results in a fast, explicit error message on the CLI within 15s, not a hang.
  • The shared DECO_TUNNEL_SERVER_TOKEN constant is removed from the CLI source.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with apps/mesh/src/cli/commands/link.ts and apps/mesh/src/auth/index.ts, then inspect the @deco-cx/warp-node register handshake and its handling of Connected.registered. Confirm how the Warp server can validate the OAuth token and report rejection. Done means end-to-end linking works without the shared key and invalid or missing tokens fail explicitly within 15 seconds.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
authentication, backend-api-design, cli, networking
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.