# services/auth-service ## Purpose The `auth-service` module owns the `AuthService` interface, its constructor (`createAuthService`), and the side-effect module augmentation that adds the `authService` slot to `@suaveplan/api-plugin/service-registry`'s `ServiceRegistry`. Together they let sibling plugins resolve the current principal and the underlying Better-Auth instance with full type safety — no casts at the call site. ## Features - `AuthService` interface with three methods: `getCurrentPrincipal(c)`, `getBetterAuthInstance()`, and `getSession(headers)`. - `createAuthService` constructor wired to a Better-Auth instance and consumed exclusively by `createAuthPlugin`'s `onInit`. - Side-effect module augmentation in `./registry-augmentation.ts` so importing anything from `@suaveplan/api-plugin-auth` makes `ctx.getService("authService")` type-narrow to `AuthService | undefined`. ## Usage: Basic ```ts import { createAuthService } from "@suaveplan/api-plugin-auth/services/auth-service"; const service = createAuthService({ auth }); const principal = service.getCurrentPrincipal(c); ``` ## Usage: Advanced From a sibling plugin's `onInit`, resolve the service and use it to authenticate a stand-alone request (e.g. a queued job that carries a serialised cookie jar): ```ts import { definePlugin } from "@suaveplan/api-plugin"; import type { Principal } from "@suaveplan/api-plugin-auth/principal/principal"; export const vaultPlugin = definePlugin({ name: "vault", version: "0.1.0", dependencies: ["auth"], async onInit(ctx) { const authService = ctx.getService("authService"); if (!authService) { throw new Error("authService not registered — is the auth plugin enabled?"); } const headers = new Headers(savedCookieJar); const result = await authService.getSession(headers); if (result === null) return; // result.user / result.session are typed via BetterAuthSessionResult }, }); ``` ## API Reference ### `interface AuthService` - `getCurrentPrincipal(c: Context): Principal | null` — reads `c.get("user")`; returns `null` for anonymous requests. - `getBetterAuthInstance(): Auth` — returns the Better-Auth instance constructed by `createAuthPlugin`. - `getSession(headers: Headers): Promise` — resolves a Better-Auth session from arbitrary request headers, useful outside the request scope. ### `type BetterAuthSessionResult` `{ user: Record; session: Record } | null`. ### `interface CreateAuthServiceOptions` `{ auth: Auth }`. ### `function createAuthService(options): AuthService` Pure constructor — wraps the Better-Auth instance with the three-method service shape. ### Module augmentation `./registry-augmentation.ts` declares `declare module "@suaveplan/api-plugin/service-registry" { interface ServiceRegistry { authService: AuthService } }`. Side-effect import. ## Implementation Notes - The service holds a reference to the Better-Auth instance — call sites that need the raw handler (e.g. the Hono catch-all route installed by `createAuthPlugin`) reach for `getBetterAuthInstance().handler` rather than re-constructing the Better-Auth client. - `BetterAuthSessionResult` is intentionally loose because Better-Auth plugins (organisations, passkeys, twoFactor) extend the `session` row with additional fields. The auth plugin's own `Principal` mapping decides which of those fields surface to consumers. - Session resolution is asynchronous; downstream plugins that want a synchronous principal-read use `getCurrentPrincipal(c)` from inside a Hono handler instead.