Files
skills/docs/api-stack/api/api-auth-better-auth/src/options/options.md
2026-05-29 08:20:56 +01:00

4.4 KiB

options

(no submodules)

Purpose

Zod-validated boundary for the Better-Auth adapter's configuration bag. Both createBetterAuthSession and createBetterAuthProvider accept the same {@link BetterAuthOptions} shape so a single options object can be threaded through host configuration even when the operator wires only one side of the auth split. Validation fires at factory-construction time so misconfiguration fails fast at boot instead of surfacing as a confusing runtime error on the first inbound request.

Features

  • Required fields — database (opaque pass-through to Better-Auth), baseUrl (URL-validated), secret (>= 16 chars).
  • Optional fields — routePrefix (/auth by default, must start with /), oauth.providers (per-provider URL-validated client config), session (cookie tuning), principalMapping (pluggable user → Principal).
  • Test hook — betterAuthFactory lets unit tests stub the underlying betterAuth(...) call without standing up a real database.

Usage: Basic

import { parseBetterAuthOptions } from "@suaveplan/api-auth-better-auth/options";

const opts = parseBetterAuthOptions({
    database: pool, // Better-Auth-shaped value (pg.Pool, Kysely dialect, …)
    baseUrl: "https://api.example.com",
    secret: process.env.BETTER_AUTH_SECRET!,
});

Usage: Advanced

import { parseBetterAuthOptions } from "@suaveplan/api-auth-better-auth/options";
import type { Principal } from "@suaveplan/api-types/principal";

const opts = parseBetterAuthOptions({
    database: pool,
    baseUrl: "https://api.example.com",
    routePrefix: "/api/auth",
    secret: process.env.BETTER_AUTH_SECRET!,
    oauth: {
        providers: {
            github: {
                providerId: "github",
                clientId: process.env.GITHUB_CLIENT_ID!,
                clientSecret: process.env.GITHUB_CLIENT_SECRET!,
                scopes: ["read:user", "user:email"],
                authorizationUrl: "https://github.com/login/oauth/authorize",
                tokenUrl: "https://github.com/login/oauth/access_token",
                userInfoUrl: "https://api.github.com/user",
            },
        },
    },
    session: { cookieName: "ba.session", cookieSameSite: "lax", cookieSecure: true },
    principalMapping: ({ user }): Principal => ({
        id: user.id as never,
        scopes: (user.roles ?? []) as never[],
        claims: { email: user.email },
    }),
});

API Reference

Export Shape Purpose
BetterAuthOptionsSchema Zod schema Validates the full options object
parseBetterAuthOptions(raw) (unknown) => BetterAuthOptions Parse + throw on failure
DEFAULT_ROUTE_PREFIX "/auth" Default mount prefix
DEFAULT_COOKIE_NAME "better-auth.session" Default cookie name
BetterAuthOptions interface Outer options shape
BetterAuthOauthProvider interface Per-provider OAuth config
BetterAuthSessionOptions interface Cookie tuning bag
BetterAuthUserView / BetterAuthSessionRecord / BetterAuthSessionView interfaces Mapper input shape
BetterAuthLike interface Structural slice of better-auth's Auth
PrincipalMapping function type (view) => Principal

Implementation Notes

database is intentionally typed as unknown and the schema only checks non-null/non-undefined — Better-Auth itself supports pg.Pool, Kysely Dialect, D1Database, DBAdapterInstance and several other shapes; the wrapper never inspects this value beyond passing it through to betterAuth({ database }). This keeps the wrapper one-driver-agnostic and lets operators bring their own connection topology (transaction-pool, single client, serverless adapter, …) without the wrapper opinionating on it.

secret enforces a 16-character floor because Better-Auth uses it for cookie signing and shorter secrets are trivially brute-forced. The exact constant is informational — Better-Auth itself would still accept shorter strings — so the strict check here is a defence-in-depth guard at the wrapper boundary.

betterAuthFactory is the only sanctioned way to inject a stubbed Better-Auth instance into the adapter. Production callers MUST omit it so the real betterAuth(...) import drives the runtime; tests use it to swap in a synchronous in-memory stub conforming to {@link BetterAuthLike}.