[PR #8548] feat(auth): support function-based dynamic baseURL config #16300

Open
opened 2026-04-13 10:29:16 -05:00 by GiteaMirror · 0 comments
Owner

Original Pull Request: https://github.com/better-auth/better-auth/pull/8548

State: open
Merged: No


Summary

Allow baseURL to accept (request: Request) => Awaitable<string> for multi-tenant and white-label apps where valid domains are stored in a database and not known at deploy time. This completes the work started in #8009 (allowedHosts), which only covers static domain lists.

  • Extends BaseURLConfig type to include function variant alongside string and DynamicBaseURLConfig
  • Reuses the per-request context isolation (Object.create) from the allowedHosts feature — no new architecture
  • Resolves the function to a string before downstream consumers access ctx.context.options.baseURL, so plugins, routes, and cookies need zero changes
  • Wraps user function errors in BetterAuthError with cause for debuggability
  • Simplifies MCP plugin's baseURL resolution from 3-way dispatch to 2-way

Test plan

  • 13 unit tests: type guards, sync/async resolution, error wrapping with cause preservation, invalid URL, null/undefined returns
  • 11 integration tests: context-level (baseURL resolution, async functions, concurrent isolation, trustedOrigins, crossSubDomainCookies) and behavioral (OAuth redirect_uri, handler error propagation, CSRF origin validation, Set-Cookie domain)
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm format:check passes

Fixes #4151


Summary by cubic

Add per-request function support for baseURL to enable multi-tenant and white-label setups where domains are resolved at runtime. Improves trusted-origin handling, cookies, OAuth/CSRF behavior, with updated docs and tests.

  • New Features
    • baseURL now accepts (request: Request) => Awaitable<string>, resolved per request and applied to ctx.context.baseURL and ctx.context.options.baseURL with per-request context isolation.
    • URL utils: added resolveFunctionBaseURL, isFunctionBaseURLConfig, and isPerRequestBaseURL; core, cookies, and mcp plugin use these for function resolution.
    • Trusted origins and cookies: resolved origin is auto-added for function configs; cross-subdomain cookies derive domain per request; OAuth redirect_uri and CSRF checks use the resolved host.
    • Validation and errors: empty/invalid URLs are rejected; function errors are wrapped in BetterAuthError with cause; clearer error messages; docs expanded with function patterns and security guidance (unsafe Host header examples removed); unit and integration tests added (sync/async, isolation, OAuth, CSRF, Set-Cookie).

Written for commit a3671edddb. Summary will update on new commits.

**Original Pull Request:** https://github.com/better-auth/better-auth/pull/8548 **State:** open **Merged:** No --- ## Summary Allow `baseURL` to accept `(request: Request) => Awaitable<string>` for multi-tenant and white-label apps where valid domains are stored in a database and not known at deploy time. This completes the work started in #8009 (allowedHosts), which only covers static domain lists. - Extends `BaseURLConfig` type to include function variant alongside string and `DynamicBaseURLConfig` - Reuses the per-request context isolation (`Object.create`) from the allowedHosts feature — no new architecture - Resolves the function to a string before downstream consumers access `ctx.context.options.baseURL`, so plugins, routes, and cookies need zero changes - Wraps user function errors in `BetterAuthError` with `cause` for debuggability - Simplifies MCP plugin's baseURL resolution from 3-way dispatch to 2-way ## Test plan - [x] 13 unit tests: type guards, sync/async resolution, error wrapping with cause preservation, invalid URL, null/undefined returns - [x] 11 integration tests: context-level (baseURL resolution, async functions, concurrent isolation, trustedOrigins, crossSubDomainCookies) and behavioral (OAuth redirect_uri, handler error propagation, CSRF origin validation, Set-Cookie domain) - [x] `pnpm typecheck` passes - [x] `pnpm lint` passes - [x] `pnpm format:check` passes Fixes #4151 <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Add per-request function support for `baseURL` to enable multi-tenant and white-label setups where domains are resolved at runtime. Improves trusted-origin handling, cookies, OAuth/CSRF behavior, with updated docs and tests. - **New Features** - `baseURL` now accepts `(request: Request) => Awaitable<string>`, resolved per request and applied to `ctx.context.baseURL` and `ctx.context.options.baseURL` with per-request context isolation. - URL utils: added `resolveFunctionBaseURL`, `isFunctionBaseURLConfig`, and `isPerRequestBaseURL`; core, cookies, and `mcp` plugin use these for function resolution. - Trusted origins and cookies: resolved origin is auto-added for function configs; cross-subdomain cookies derive `domain` per request; OAuth `redirect_uri` and CSRF checks use the resolved host. - Validation and errors: empty/invalid URLs are rejected; function errors are wrapped in `BetterAuthError` with `cause`; clearer error messages; docs expanded with function patterns and security guidance (unsafe Host header examples removed); unit and integration tests added (sync/async, isolation, OAuth, CSRF, Set-Cookie). <sup>Written for commit a3671edddb7c91fcfa0b7fe47df4dc250520e70f. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. -->
GiteaMirror added the pull-request label 2026-04-13 10:29:16 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#16300