# Generated records-service auth integration

> This file is generated from the live auth and records-service source files. Do not edit it by hand; regenerate it from `apps/docs-site/` with `bun run generate`.

Generated from: `apps/core/auth/src/platform/better-auth/auth.ts`, `apps/core/auth/src/index.ts`, `apps/delta/records-service/src/index.ts`, `apps/delta/records-service/src/middleware/surreal-auth.ts`, `apps/delta/application-list/src/features/forms-management/forms-api.ts`, `apps/delta/audits/src/platform/service-clients/api-client.ts`, `packages/auth/permissions/src/hono.ts`, `packages/database/migrations/migrations/0123_nela_scoped_jwt_access.surql`

![Forms-service auth flow](../../diagrams/generated/records-service-auth-flow.svg)

- [Open flow SVG](../../diagrams/generated/records-service-auth-flow.svg)
- [Open Mermaid source](../../diagrams/generated/records-service-auth-flow.mmd)
- [Open generated auth runtime summary](./auth-runtime.md)

## What this page is tracing

- The browser-side Better Auth client call that retrieves a JWT for `records-service`.
- The point where `records-service` verifies that JWT with auth-service JWKS and Better Auth-backed security rules.
- The handoff where the same token becomes a SurrealDB-authenticated connection through `db.authenticate(token)`.
- The optional token-exchange branch for non-`crown` databases such as `nela`.

## Flow checkpoints

- The browser retrieves a Better Auth JWT with `authClient.token()` before it calls protected `records-service` routes.
- `records-service` mounts `surrealAuthMiddleware` on `/api/*` before route handlers, so auth runs before business logic touches request state.
- `createAuthMiddleware()` verifies the JWT with auth-service JWKS and can rehydrate Better Auth session data when route logic needs current active context rather than raw token claims alone.
- The middleware can also call back into auth-service for active organization / workspace / team context, so Better Auth remains the source of truth for scope resolution.
- The current `records-service` middleware uses the same JWT directly against SurrealDB by creating a request-scoped connection and calling `db.authenticate(token)`.
- If a service needs a non-default database, auth-service can exchange the token first; the live target list currently includes `nela`.

## Frontend token handoff examples

- `apps/delta/audits/src/platform/service-clients/api-client.ts` calls `authClient.token()` and sends `Authorization: Bearer <jwt>`.

## Better Auth modules shaping this path

| Module | Why it matters to `records-service` |
| --- | --- |
| JWT | Signs the downstream token, exposes JWKS, and defines the Surreal-facing `ns` / `db` / `ac` claims. |
| Two Factor | Adds the second-factor state that surfaces as `twoFactorEnabled`, which `records-service` requires before protected access. |
| Email OTP | Drives verification and recovery OTP flows that ultimately feed the `emailVerified` claim the middleware enforces. |
| Organization | Keeps organization and team membership inside the Better Auth session that downstream services can rehydrate. |
| Workspace | Adds active workspace and team context so downstream services know which scope the user is operating in. |
| Permissions | Feeds the role-template and custom-permission pipeline that becomes the request `ability` in `records-service`. |
| Admin Access | Adds privileged admin flows on top of the same Better Auth runtime, even though ordinary forms traffic only consumes the signed JWT output. |
| External Structure | Extends Better Auth with partner and delegated-access context that rides beside the same JWT/session model. |
| Organization Archive | Extends organization lifecycle handling inside auth-service without changing how `records-service` verifies tokens. |

## JWT claims detected in the auth app

The current Better Auth JWT payload includes: `ns`, `db`, `ac`, `sub`, `id`, `email`, `role`, `null`, `emailVerified`, `twoFactorEnabled`, `false`, `twoFactorMethod`, `twoFactorMethods`, `activeWorkspaceId`, `activeOrganizationId`, `activeTeamId`, `orgRole`, `teamRole`.

Those claims matter because the token is not only verified at the HTTP edge; it is also reused by SurrealDB, where ACCESS policies can inspect values such as `$token.ns`, `$token.db`, `$token.ac`, and `$token.sub`.

## Where Better Auth sits relative to records-service

- Better Auth itself lives inside `auth-service`; `records-service` does **not** run Better Auth directly.
- The browser asks Better Auth for a JWT through the client SDK, then forwards that JWT to `records-service`.
- `records-service` trusts only tokens that validate against auth-service JWKS and match the expected issuer/audience.
- Crown Better Auth extensions such as workspace, organization, and permissions shape the active scope and permission context that downstream middleware consumes.
- `@crown/better-auth-permissions` is the bridge that turns the Better Auth token/session world into `userDb`, `userContext`, and `ability` on the Hono request.

## Source checkpoints

| Stage | Evidence | What it proves |
| --- | --- | --- |
| Browser gets a JWT | `apps/delta/application-list/src/features/forms-management/forms-api.ts`, `apps/delta/audits/src/platform/service-clients/api-client.ts` | Frontend code calls `authClient.token()` and forwards the JWT as a bearer token before it calls `records-service`. |
| Better Auth signs the token | `apps/core/auth/src/platform/better-auth/auth.ts` | The current JWT lifetime is `15m` and the keypair uses EdDSA / Ed25519. |
| records-service guards `/api/*` | `apps/delta/records-service/src/index.ts`, `apps/delta/records-service/src/middleware/surreal-auth.ts` | The middleware requires `verified email` + `two-factor enabled` before protected routes run. |
| JWT becomes request context | `packages/auth/permissions/src/hono.ts` | `createAuthMiddleware()` verifies JWKS, resolves Better Auth session/context, loads custom roles, and builds the request `ability`. |
| Same JWT reaches Surreal | `packages/auth/permissions/src/hono.ts`, `apps/delta/records-service/src/middleware/surreal-auth.ts` | The shared auth middleware authenticates the underlying Surreal connection with the request token. |
| Alternate DB tokens | `apps/core/auth/src/index.ts`, `packages/database/migrations/migrations/0123_nela_scoped_jwt_access.surql` | The token exchange route can mint a database-specific JWT, and the `nela` access migration shows Surreal validating `db = nela` and `ac = nela`. |

## Alternate database note

The current `records-service` configuration points `createSurrealAuthMiddleware()` at the default `crown` database, so it uses the incoming Better Auth JWT directly. The token-exchange route still matters because the middleware can request a new JWT before calling `db.authenticate()` when a service needs a different Surreal database or access scope.

## Generation note

- This page is regenerated from the auth app, `records-service`, and the shared auth middleware.
- If the token shape, security gates, or Surreal authentication path change, the next docs generation run updates this page and its flow diagram automatically.
