Authentication

better-auth integration and the withAuthSession helper for authenticating requests inside handlers.

thunder-core builds authentication on better-auth. lib/auth.ts exports a configured better-auth instance (auth) plus betterAuthConfig and capabilities.

better-auth Configuration

The instance uses the MongoDB adapter with plural collection names and enables the admin, passkey, twoFactor, magicLink, and multiSession better-auth plugins. Behaviors worth knowing:

  • New users get a Gravatar image fallback derived from a SHA-256 hash of their email.
  • Signup is blocked unless signup is in BETTER_AUTH_CAPABILITIES.
  • Password-reset and magic-link emails are sent via the Mailer.
  • better-auth is mounted under the auth route; its handler base path is /auth/api, so better-auth client SDKs should target that base URL.

Read lib/auth.ts for the exact configuration, and routes/auth.ts for the branding/capabilities endpoints and the better-auth UI fallback.

Authenticating a Request - withAuthSession

utils/withAuthSession.ts is the primary helper for authenticating a request inside a handler. It supports three credential strategies, checked in order, and memoizes the result per-request:

  1. OAuth2 Bearer token (Authorization: Bearer <access_token>) - verified via OAuth2.verifyAccessToken; scopes come from the consent (optionally narrowed per tenant via the consent's resourceGrant[tenantId]).
  2. API key (X-Api-Key: <secret>) - resolved via APIKey.resolve; scopes from the key (optionally narrowed per tenant via resourceGrant).
  3. Session cookie - resolved via auth.api.getSession(req).
import { withAuthSession } from "@/plugins/Huruf-Tech/thunder-core/utils/withAuthSession.ts";

const { user, session, tenantId, scopes, auth } = await withAuthSession(req);

// Pass `true` for silent mode (returns void instead of throwing 401 when unauthenticated):
const maybe = await withAuthSession(req, true);
  • tenantId is read from the X-TENANT-ID request header (an ObjectId).
  • It throws Response.unauthorized() on failure unless silent is true.

See utils/withAuthSession.ts for the exact return type. utils/withCachedOnRequest.ts is the underlying per-request memoization helper (a WeakMap<Request, ...>) - use it to cache expensive per-request computations by key.


On this page