Better Auth¶
An app with a web UI and its own users signs in with Better Auth, set up stricter than its defaults: links, codes and tokens stored hashed, no session tokens as bearer tokens, telemetry off, and its tables in their own SQLite file.
Why¶
Better Auth is an open-source (MIT) library that runs in the app's process: accounts, sessions, magic links, email codes, passkeys, any OpenID Connect provider, and an OAuth server for MCP clients. It keeps sign-in code out of each app. Some of its defaults are weaker than these conventions, so each app sets them. The architecture is on Sign-in.
How¶
- Database: its own file,
DATA_DIR/auth.sqlite, next to the app's data. The app's tables carry Better Auth'suser.idas the user id; deleting a user deletes their data in anafterhook. - Sign-in methods: OpenID Connect providers from the app's own env vars (
<APP>_OIDC_<NAME>_ISSUER,_CLIENT_ID,_CLIENT_SECRET,_LABEL), built-in providers for Google and Apple,genericOAuthfor the rest; magic link and email code (email-otp) sent through the app's SMTP settings; passkeys (@better-auth/passkey), added while signed in. - MCP:
@better-auth/mcpwith@better-auth/cimd; tokens bound to the MCP resource. Dynamic client registration only when a client needs it (claude.ai does). - Backends: the
jwtplugin; backends check its tokens against/api/auth/jwks. - Identity: verified email by default, with
trustedProviders;disableImplicitLinkingwhen a second sign-in must be linked by hand. - Settings that differ from the defaults:
storeToken: "hashed"for magic links andstoreOTP: "hashed"for email codes;- no
bearerand nodevice-authorizationplugin: Better Auth stores session tokens in plain text, and without thebearerplugin a copied one is useless, because the cookie must carry a signature made with the secret; - an email holds only a code during an MCP or script sign-in;
- telemetry stays off (nothing sets
telemetry.enabledorBETTER_AUTH_TELEMETRY); - the secret comes from the app's own env var and is passed in.
- Pages: Better Auth ships none. The app builds its sign-in and consent pages in its own design, against Better Auth's client.
Rules out¶
- Hand-written sign-in, session or OAuth code next to Better Auth.
- The
bearerordevice-authorizationplugin. - Plain-text magic links or codes; telemetry turned on.
- Better Auth's tables in the app's data file.
Reference¶
questlog ADR 0004 (sign-in with Better Auth, in its own SQLite file).