Skip to content

fix(proxy): allow /.well-known/* and /embed/* on self-hosted#1874

Open
kovashikawa wants to merge 3 commits into
CapSoftware:mainfrom
kovashikawa:fix/proxy-allow-well-known-self-hosted
Open

fix(proxy): allow /.well-known/* and /embed/* on self-hosted#1874
kovashikawa wants to merge 3 commits into
CapSoftware:mainfrom
kovashikawa:fix/proxy-allow-well-known-self-hosted

Conversation

@kovashikawa
Copy link
Copy Markdown

@kovashikawa kovashikawa commented May 30, 2026

Summary

  • Two-line fix: add /.well-known/ and /embed/ to the self-host proxy whitelist.
  • Restores all workflow execution on self-hosted Cap (transcription, AI generation, etc.) and fixes broken iframe embeds.

Root cause

apps/web/proxy.ts:40-58 redirects every path not in an allow-list to /login when NEXT_PUBLIC_IS_CAP !== "true" (i.e., self-hosted builds). /.well-known/ and /embed/ were both missing from that list.

/.well-known/ (workflows broken)

The Vercel Workflows runtime that Cap uses (apps/web/app/.well-known/workflow/v1/{step,flow,webhook}/route.js) dispatches workflow steps by issuing HTTP requests back to itself at those routes. On self-host, those requests get a 307 → /login, so workflows are enqueued but never run.

Visible symptom: transcribeVideo() is called and logs [transcribeVideo] Triggering transcription workflow…, but no subsequent [transcribe] step lines ever appear, no Deepgram/Whisper request is made, and videos.transcriptionStatus stays NULL forever. Same for aiGenerationStatus.

/embed/ (iframe embeds broken)

<iframe src=".../embed/..."> embeds on self-hosted instances load the login page instead of the embedded video, because the embed route also fails the proxy whitelist check.

Fix

// apps/web/proxy.ts
path.startsWith("/verify-otp") ||
path.startsWith("/.well-known/") ||  // ← added (commit 1)
path.startsWith("/embed/")           // ← added (commit 2)

That's it. The matcher in config.matcher already excludes _next/* etc., and both prefixes are scoped to existing app routes, so widening is safe.

Verification

Reproduced on a local Docker Compose self-host (docker-compose.yml).

Before this patch

  • curl http://localhost:3000/.well-known/workflow/v1/manifest.json returns the Next.js HTML shell (the redirect-to-login response).
  • Uploading a video, then triggering transcription via the share page or POST /api/videos/:id/retry-transcription, leaves transcriptionStatus = NULL forever.

After this patch

  • Same curl returns the workflow manifest JSON (correct route).
  • Share-page render fires transcribeVideo(); the workflow runs end-to-end: audio extraction → transcription provider → transcription.vtt written to S3 → transcriptionStatus = COMPLETE. AI generation then runs and writes metadata.summary + metadata.chapters.

Related

Greptile Summary

Two-line whitelist addition to the self-hosted proxy gate in proxy.ts, restoring /.well-known/ workflow callbacks and /embed/ iframe routes that were incorrectly redirected to /login.

  • /.well-known/ allows the Vercel Workflows runtime to call back to its own step/flow/webhook routes without being bounced; without this, transcription and AI generation workflows are silently enqueued but never execute.
  • /embed/ allows unauthenticated access to embedded video player routes, which is the correct behaviour for public embeds on self-hosted instances.

Confidence Score: 4/5

Safe to merge; the fix is minimal, targeted, and correctly scoped to routes that must be publicly reachable on self-hosted deployments.

The change is two lines in one file and the logic is easy to verify against the described failure. The only open question is whether the /.well-known/workflow/v1/webhook handler validates Vercel's request signature independently, since prefix matching now makes the entire /.well-known/ tree reachable without the proxy auth check.

The workflow route handlers under apps/web/app/.well-known/workflow/v1/ are worth a quick glance to confirm they verify the incoming request signature before acting.

Important Files Changed

Filename Overview
apps/web/proxy.ts Adds /.well-known/ and /embed/ to the self-host proxy auth bypass list; straightforward fix with prefix-match breadth worth noting
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
apps/web/proxy.ts:54-55
**Broad bypass scope for future routes**

Both new entries use prefix matching, so every future route added under `/.well-known/` (including any webhook handler) and `/embed/` will automatically bypass the self-host auth redirect — with no indication at the call site that this is happening. The `/.well-known/workflow/v1/webhook` route in particular is publicly reachable as a result; its safety depends entirely on Vercel Workflow's own request-signing, which isn't visible here. Worth confirming the webhook handler validates the signature before relying on this being safe.

Reviews (1): Last reviewed commit: "fix(proxy): allow /embed/* on self-hoste..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

The self-hosted proxy whitelist (active when NEXT_PUBLIC_IS_CAP !== "true")
did not include /.well-known/, so the Vercel Workflows runtime — which
dispatches itself via HTTP to /.well-known/workflow/v1/{step,flow,webhook} —
was 307-redirected to /login on every call. The transcription workflow
starts, the workflow runtime enqueues the first step, the HTTP callback is
intercepted, and no step ever executes.

Symptom on self-host: video uploads succeed, transcription is never
performed, AI features never run. Logs show transcribeVideo() being called
but no `[transcribe]` step lines and no Deepgram/Whisper request ever fires.

Adding /.well-known/ to the same whitelist that already includes /api,
/login, etc. restores the workflow callback path.

Resolves CapSoftware#1774. Root cause behind self-host AI breakage reported in CapSoftware#1356
and CapSoftware#1550.
The self-hosted proxy whitelist (active when NEXT_PUBLIC_IS_CAP !== "true")
did not include /embed/, so embed routes were 307-redirected to /login.
This broke <iframe src=".../embed/..."> embeds on every self-hosted
instance — the iframe loads the login page instead of the embedded video.

Same root cause and fix shape as the prior commit (/.well-known/): a path
prefix that needs to be on the public allow-list was missing.

Resolves CapSoftware#1768.
Comment thread apps/web/proxy.ts Outdated
Per review feedback on CapSoftware#1874: the original prefix `/.well-known/` would
auto-bypass the self-host auth redirect for any future route added under
`.well-known/` (ACME challenges, OIDC discovery, etc.). The only subtree
the Vercel Workflows runtime needs is `/.well-known/workflow/`, so scope
the bypass exactly to that.

Webhook auth still relies on `resumeWebhook(token, request)` in the
framework-generated `/.well-known/workflow/v1/webhook/[token]/route.js`,
which validates the token in-handler. Step/flow routes carry their own
signature verification. This commit just narrows the proxy bypass; it
does not change the underlying request-auth guarantees.
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.

/.well-known/workflow/v1/* routes blocked by proxy whitelist on self-hosted /embed/* routes redirect to /login on self-hosted, breaking iframe embeds

1 participant