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

3.0 KiB

session-without-provider

(no submodules)

Purpose

Pin the design invariant from The spec change: the Better-Auth adapter ships two factories — createBetterAuthSession and createBetterAuthProvider — and operators MUST be able to wire either side without dragging in the other. Wiring only the session adapter (keeping account-lifecycle elsewhere — e.g. Clerk or a custom rolled provider) is the "hosted IdP for accounts, Better-Auth for session reads against a shared cookie" topology the design doc §2.3 calls out. Wiring only the provider adapter (no Better-Auth session resolution) is rarer but legal — the host fills the auth.session slot with whatever other resolver is configured.

Features

  • Sibling test file pins the invariant by:
    • Asserting createBetterAuthSession(opts) returns a SessionResolver with no routes / pathPrefix field.
    • Asserting createBetterAuthProvider(opts) returns an AuthProviderAdapter with no resolve / dispose field.
    • Walking the recorded route list when routes(...) IS invoked to verify every canonical name lands.
  • betterAuthFactories constant re-exports both factories as a single bag so consumer documentation can name the pair without repeating imports.

Usage: Basic

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

const resolver = betterAuthFactories.session(opts);
const provider = betterAuthFactories.provider(opts);

Usage: Advanced

import { createBetterAuthSession } from "@suaveplan/api-auth-better-auth";
import { ClerkSessionResolver } from "third-party/clerk-suaveplan-adapter";

// Topology: Clerk owns sign-up / sign-in routes; Better-Auth reads the
// shared session cookie via createBetterAuthSession against a shadow
// Better-Auth DB that mirrors the Clerk user store. Provider side NOT wired.
host.registerAuth({
    resolver: new SessionResolverChain({
        resolvers: [
            createBetterAuthSession({ database: pool, baseUrl, secret }),
            new ClerkSessionResolver({ clerkApiKey: process.env.CLERK_KEY! }),
        ],
    }),
});

API Reference

Export Shape Purpose
betterAuthFactories Readonly<{ session, provider }> Convenience bag pairing both factories

Implementation Notes

The module is intentionally near-empty — the invariant lives in the test file. The thin re-export bag is the only runtime contribution because the OpenSpec scaffolding rule requires every implementation file to have a sibling .md AND a paired test file. The independence is enforced structurally by TypeScript anyway — SessionResolver and AuthProviderAdapter have disjoint shapes — but the test pin guards against a refactor that accidentally adds an if-not-mounted-mount-the-other-side side effect inside either factory. The OpenSpec spec delta lists this file as the verification for the "session-only / provider-only wiring exposes nothing from the other side" scenario, so the test names match the spec exactly.