Skip to main content
← Back to list
01Issue
BugShippedSwamp CLI
Assigneeskeeb

Better Auth rejects requests on hostnames not in hardcoded trustedOrigins (signup/signin broken on non-canonical hosts)

Opened by keeb · 4/27/2026· Shipped 4/27/2026

Summary

After PR #470 (multi-hostname feature), Better Auth rejects every state-changing request with ERR: Invalid origin when the inbound Origin header is anything other than the four hardcoded entries:

  • https://swamp.club
  • https://swamp-club.com
  • http://localhost:8000
  • http://127.0.0.1:8000

This breaks signup, signin, password reset, and email verification on any deployment running on a different host:

  • UAT (Playwright suite in web-deploy.yml): the harness picks a free port via findFreePort() and runs the app at e.g. http://localhost:40669. Every signup-touching test fails. With workers: 1 and retries: 2, all 29 specs hit the failure path × 3 attempts × ~40s of compose-up/teardown per cycle ≈ ~58 min worst case (the "Web: Deploy" step appears stuck in a loop). Confirmed locally — captured ERR: Invalid origin in the Playwright error-context.md from tests/club/flows/email_signup.spec.ts.
  • Any preview/staging/tunnel deployment that doesn't set TRUSTED_ORIGINS.

Steps to reproduce

  1. Check out main at 6042191 (or any commit after #470).
  2. cd swamp-uat && SWAMP_CLUB_SOURCE_DIR=/path/to/swamp-club CI=true deno run -A npm:playwright test --project=club --workers=1 tests/club/flows/email_signup.spec.ts --reporter=line
  3. Test fails: expect(page).toHaveURL(/\/check-email/) — page stays on /signup.
  4. Inspect test-results/.../error-context.md — DOM contains <alert>ERR: Invalid origin</alert>.

Root cause

lib/auth.ts:48-56 hardcodes the trustedOrigins list. The previous version included ...(authURL ? [authURL] : []) to add BETTER_AUTH_URL to the allowlist; that line was dropped in 0f8842c when the multi-hostname code landed.

Suggested fix (one line)

const authURL = Deno.env.get("BETTER_AUTH_URL");
const trustedOrigins = Array.from(
  new Set([
    "https://swamp.club",
    "https://swamp-club.com",
    "http://localhost:8000",
    "http://127.0.0.1:8000",
    ...(authURL ? [authURL] : []),
    ...extraTrustedOrigins,
  ]),
);

UAT compose already sets BETTER_AUTH_URL: http://localhost:${HOST_PORT} (the random port), so this restores the previous behavior without affecting production multi-hostname routing.

Environment

  • swamp-club: 6042191 (main)
  • swamp-uat: 1096f53 (main)
  • Node/Deno: pinned per workflow (deno 2.7.11)
  • Playwright: 1.59.1 / 1.58.2
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 9 MOREFINDINGS+ 3 MOREPR_MERGEDSHIPPED

Shipped

4/27/2026, 10:47:27 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
keeb assigned keeb4/27/2026, 9:43:58 PM

Sign in to post a ripple.