Skip to content

fix(self-hosting): pass CAP_CHROME_EXTENSION_ID through to the web container (#1993)#2035

Open
DPS0340 wants to merge 1 commit into
CapSoftware:mainfrom
DPS0340:fix/self-host-chrome-extension-id
Open

fix(self-hosting): pass CAP_CHROME_EXTENSION_ID through to the web container (#1993)#2035
DPS0340 wants to merge 1 commit into
CapSoftware:mainfrom
DPS0340:fix/self-host-chrome-extension-id

Conversation

@DPS0340

@DPS0340 DPS0340 commented Jul 25, 2026

Copy link
Copy Markdown

Fixes #1993.

Problem

CAP_CHROME_EXTENSION_ID is declared in the env schema (packages/env/server.ts:82) and is load-bearing for extension login, but it is not mapped into the cap-web service in either compose file. Self-hosters have no supported way to set it, so extension login always fails.

The failure is not a soft one. validateExtensionRedirectUri (packages/web-backend/src/Extension/Http.ts) only tolerates an unpinned extension id on localhost:

const configuredExtensionId = serverEnv().CAP_CHROME_EXTENSION_ID;

if (configuredExtensionId) {
  if (extensionId !== configuredExtensionId) return yield* new HttpApiError.BadRequest();
  return url;
}

// ...localhost-only fallback
const isLocalDevelopment =
  serverEnv().NODE_ENV !== "production" &&
  (webHostname === "localhost" || webHostname === "127.0.0.1");

if (!isLocalDevelopment) return yield* new HttpApiError.BadRequest();

That check is correct and I have deliberately not touched it — the comment above it explains why, and it's right: without a pinned id, any installed extension could mint auth keys for a signed-in user. The bug is purely that a self-hosted deployment has no way to satisfy it, so every redirect URI is rejected with the 400 the reporter saw.

Fix

Three mechanical additions, no logic changes:

  • docker-compose.yml — pass CAP_CHROME_EXTENSION_ID: ${CAP_CHROME_EXTENSION_ID:-} to cap-web, matching how the other optional integrations (GOOGLE_CLIENT_ID, APPLE_CLIENT_SECRET, RESEND_API_KEY) are wired.
  • docker-compose.coolify.yml — same.
  • docker-compose.coolify.env.example — a documented, empty entry so it's discoverable.

Plus a Chrome Extension section in self-hosting.mdx, next to the existing Google/Apple OAuth sections, explaining what the value is, why it's required, and where to find it.

Defaulting to empty (:-) keeps the current behaviour for anyone not using the extension: the var stays unset, the schema treats it as optional(), and nothing changes.

Notes

I left docker-compose.template.yml alone — it's a minimal template that doesn't carry the OAuth or Resend vars either, so adding just this one would be inconsistent with its scope.

Verification

  • Both compose files parse as valid YAML after the change, and the key resolves as expected:
    docker-compose.yml:          present=True value='${CAP_CHROME_EXTENSION_ID:-}'
    docker-compose.coolify.yml:  present=True value='${CAP_CHROME_EXTENSION_ID:-}'
    
  • No application code touched, so no type or lint surface is affected.

Diff: 4 files, +29/-0.

…ntainer

The extension auth endpoint requires a pinned extension id on any reachable
deployment — without one it rejects every redirect URI, since an unpinned id
would let any installed extension mint auth keys for a signed-in user.

The variable existed in the env schema but was never mapped into cap-web in
either compose file, so self-hosters had no supported way to set it and
extension login always failed with a 400. Document it alongside the other
optional integrations.
@DPS0340

DPS0340 commented Jul 25, 2026

Copy link
Copy Markdown
Author

@tembo please review

@DPS0340

DPS0340 commented Jul 25, 2026

Copy link
Copy Markdown
Author

Heads-up on CI: the Test Self-Hosting and CI workflows are sitting in action_required on this PR — GitHub gates workflow runs on first-time contributors until a maintainer approves them. So the checks you see green here are only the ones that don't need approval (Socket, Superagent, Contributor trust).

That matters more than usual for this change, because test-self-hosting.yml triggers specifically on docker-compose.yml and docker-compose.coolify.yml — exactly the files touched. It brings the whole stack up with docker compose up -d and waits for MySQL/MinIO health, so approving the run is a genuine end-to-end check that this doesn't break the self-host path, not a formality.

I verified locally what I could — both files parse as valid YAML and the key resolves to '${CAP_CHROME_EXTENSION_ID:-}' — but I can't run the compose stack here, so the workflow approval is the real verification.

(The red Vercel check is the usual fork-PR deploy-token issue, not related.)

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.

bug(self-hosting): Chrome extension login fails on self-hosted instances (missing CAP_CHROME_EXTENSION_ID)

1 participant