refactor: update API routing to use /proxy prefix for same-origin requests

This commit is contained in:
Rotimi Best
2026-05-20 07:03:18 +01:00
parent 1234fdb8a1
commit e97832e6d9
4 changed files with 45 additions and 23 deletions
@@ -16,10 +16,11 @@ export const getRequestBaseUrl = () => {
return process.env.PRIVATE_SERVER_URL || env.PUBLIC_SERVER_URL;
}
// Browser: same-origin via the Cloudflare Worker /api proxy. Keeps auth
// cookies host-only on whichever domain the user is currently visiting
// (app.classroomio.com, <org>.classroomio.school, or a BYOD domain).
return `${window.location.origin}/api`;
// Browser: same-origin via the Cloudflare Worker `/proxy` prefix. Keeps
// auth cookies host-only on whichever domain the user is currently
// visiting (app.classroomio.com, <org>.classroomio.school, or BYOD).
// The Worker strips `/proxy` and forwards the remainder to the API.
return `${window.location.origin}/proxy`;
};
function mergeAbortSignals(...signals: Array<AbortSignal | null | undefined>) {
@@ -2,16 +2,25 @@ import { createAuthClient } from 'better-auth/svelte';
import { env } from '$env/dynamic/public';
import { ssoClient } from '@better-auth/sso/client';
// Browser: same-origin `/api` via the Cloudflare Worker, so auth cookies
// stay host-only on whichever domain the user is currently on
// (app.classroomio.com, <org>.classroomio.school, or a BYOD domain).
// SSR: `authClient`'s methods aren't called server-side — the dashboard uses
// `authServerClient` for that — but Better Auth's constructor still validates
// the baseURL with `new URL(...)`, so we hand it the public API URL as a
// placeholder. PRIVATE_SERVER_URL is deliberately not used here: it's the
// internal Render hostname, never reachable from a browser.
// Browser: same-origin via the Cloudflare Worker, so auth cookies stay
// host-only on whichever domain the user is on (app.classroomio.com,
// <org>.classroomio.school, or a BYOD domain). The URL is
// `<origin>/proxy/api/auth`:
// - `/proxy` is the Worker's same-origin escape hatch — it strips
// that prefix before forwarding to the upstream API.
// - `/api/auth` is where Better Auth is mounted on the Hono API.
// Better Auth's client treats any baseURL with a path as the auth root
// verbatim (it won't auto-append `/api/auth`), so we encode the full
// downstream path here.
//
// SSR: `authClient` methods are never invoked server-side (the dashboard
// uses `authServerClient` for that), but Better Auth's constructor still
// validates baseURL with `new URL(...)`, so we hand it the public API
// URL as an absolute-URL placeholder.
const baseURL =
typeof window !== 'undefined' ? `${window.location.origin}/api` : env.PUBLIC_SERVER_URL || 'http://localhost:3002';
typeof window !== 'undefined'
? `${window.location.origin}/proxy/api/auth`
: env.PUBLIC_SERVER_URL || 'http://localhost:3002';
export const authClient = createAuthClient({
baseURL,