Skip to content

dev: eve dev <remote-url> can't authenticate to non-Vercel-OIDC self-hosted agents #316

Description

@pranaygp

Summary

A self-hosted, non-Vercel, auth-protected eve agent is the one configuration the remote dev REPL cannot talk to. The moment a channel adds a non-OIDC verifier (e.g. auth: [httpBasic()]), eve dev <remote-url> can no longer connect. The remote dev client only knows how to mint and attach a Vercel OIDC token (plus the Vercel preview-protection bypass header). There is no flag, env var, or URL-userinfo path to supply HTTP Basic / bearer / generic credentials to a protected remote route. For a framework whose pitch includes "not coupled to Vercel," the remote dev tooling assuming Vercel OIDC for auth is a notable gap: for a self-hosted protected agent, "usable dev/REPL UI" and "protected agent" are effectively mutually exclusive without building custom auth plumbing.

Repro

  1. Add any non-OIDC verifier to a channel, e.g. auth: [httpBasic({ username, password })] (or jwtHmac(), oidc(), etc.).
  2. Deploy/self-host the agent (not behind Vercel OIDC), behind that auth.
  3. Run eve dev https://your-host.

The REPL cannot authenticate — it has no way to present the channel's credentials. Specifically:

  • https://user:pass@host userinfo is ignored: parseDevelopmentServerUrl clears url.hash and url.search but the remote dev wiring never reads url.username/url.password (packages/eve/src/cli/dev/url.ts:36-39). No code in the dev/client remote path reads URL userinfo.
  • VERCEL_AUTOMATION_BYPASS_SECRET only addresses Vercel preview/Deployment Protection (it maps to x-vercel-protection-bypass), not arbitrary route auth (packages/eve/src/services/dev-client/credential-gate.ts:81-86, header constant at packages/eve/src/services/dev-client/request-headers.ts:99-101).

Root cause

The remote dev path is hardwired to Vercel OIDC, even though the underlying HTTP client already supports basic and bearer:

  • The remote client options builder always emits auth: { vercelOidc: ... } and the Vercel bypass headers — there is no seam to pass other credentials: packages/eve/src/services/dev-client/client-options.ts:15-31 (resolveRemoteDevelopmentClientOptions).
  • The TUI remote wiring constructs the client exclusively through that builder backed by a Vercel-only credential gate: packages/eve/src/cli/dev/tui/tui.ts:36-88.
  • The credential gate only knows two states, anonymous and vercel, and resolveToken() returns a Vercel OIDC token (or ""): packages/eve/src/services/dev-client/credential-gate.ts:31-95.
  • The entire remote-auth flow resolves a Vercel deployment and mints a project-scoped OIDC token — there is no non-Vercel credential branch at all: packages/eve/src/cli/dev/tui/remote-auth.ts:107-245.
  • Challenge detection is Vercel-specific: isVercelAuthChallenge only matches Vercel's Deployment Protection SSO HTML (a 401 carrying vercel.com/sso-api + <title>Authentication Required</title>): packages/eve/src/services/dev-client/vercel-auth-error.ts:29-69. A plain WWW-Authenticate: Basic 401 is not understood.
  • The eve dev command itself exposes no credential/header flags — only --host, --port, -u/--url, --no-ui, --name, --input, and rendering modes: packages/eve/src/cli/run.ts:435-483.

Notably the seam to fix is small, because the HTTP client (Client) already supports the needed schemes. ClientAuth is { basic } | { bearer } | { vercelOidc } (packages/eve/src/client/types.ts:48-54), and Client.#resolveAuthHeaders() already emits Authorization: Basic … / Bearer … (packages/eve/src/client/client.ts:177-211, encodeBasicCredentials at :250-255). The remote dev wiring just never reaches those branches.

Impact

For self-hosted, non-Vercel deployments, "protected" and "usable remote REPL" are mutually exclusive without building custom auth plumbing. The author of a real self-hosting writeup had to set auth: [none()] to make the demo usable. This contradicts the not-coupled-to-Vercel positioning of the framework.

Proposed fix

Give the remote dev client a credential-passthrough seam so the REPL can satisfy a protected route, reusing the schemes the channel auth helpers already expose (packages/eve/src/public/channels/auth.ts: httpBasic :889, jwtHmac :897, jwtEcdsa :906, oidc :920, vercelOidc :880). Concrete options, in rough order of effort:

  1. Repeatable --header / -H flag on eve dev (and the bare-URL form): inject arbitrary request headers. The injection point already exists — resolveRemoteDevelopmentClientOptions builds ClientOptions.headers, and Client merges base headers before auth headers (packages/eve/src/client/client.ts:155-172). Lowest-friction, scheme-agnostic.
  2. Env-based / explicit credential for Basic and bearer (e.g. an EVE_DEV_* token, or --bearer / --basic) wired into a non-Vercel branch of the credential gate, so resolveRemoteDevelopmentClientOptions can emit auth: { basic } / auth: { bearer } instead of always vercelOidc. The Client side already supports these.
  3. First-class support for the same auth schemes the channel helpers expose (httpBasic, jwtHmac/jwtEcdsa, generic oidc) so the REPL can mint/attach a matching credential for a protected route, paralleling the receiving side.
  4. Low-effort partial improvement: honor https://user:pass@host userinfo by reading url.username/url.password in the remote dev path and lowering it to auth: { basic } (today it is silently dropped).

The concrete seam for all of these is resolveRemoteDevelopmentClientOptions (packages/eve/src/services/dev-client/client-options.ts:15-31) plus the credential gate (packages/eve/src/services/dev-client/credential-gate.ts); the Client already turns ClientAuth/headers into the right outbound headers.

Workaround today

  • auth: [none()] on the channel (insecure — what the writeup resorted to), or
  • front the agent with your own proxy/credential layer that the REPL can reach unauthenticated.

This came from a self-hosting writeup and is the deepest of several self-host gaps surfaced there; the others are already addressed in PRs #306 and #308.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions