Authentication · modules/iam
Production-ready adapterBetterAuth,
behind a port.
Auth is the part a blank repo ships insecure. UseDeploy wires BetterAuth into the IAM bounded context behind a typed IAuthProvider port — with the OWASP-recommended argon2id hasher, first-class second factors, and cookie sessions from day one.
One adapter, every method
createBetterAuth wires the Prisma session adapter, the argon2id hasher backed by Bun’s native password API, and the plugins for magic links, two-factor and passkeys. Google OAuth switches on only when its client id/secret are present.
1 return betterAuth({
2 database: prismaAdapter(prisma, { provider: 'postgresql' }),
3 emailAndPassword: { enabled: true, password: argon2Hasher },
4 socialProviders: cfg.google ? { google: cfg.google } : undefined,
5 plugins: [
6 magicLink({ sendMagicLink }),
7 twoFactor({ /* TOTP */ }),
8 passkey({ /* WebAuthn */ }),
9 ],
10 });
What you get on day one
argon2id password hashing
Bun ships argon2id in core — no npm dependency. It is the OWASP-recommended default for new applications.
Magic links
Passwordless sign-in via a delivery hook that forwards to the configured email provider (or logs the link in dev).
TOTP two-factor
The two-factor plugin enrolls authenticator apps and gates sign-in with a twoFactorRedirect step.
Passkeys (WebAuthn)
The passkey plugin registers platform authenticators against your RP id / origin.
Google OAuth
Social sign-in switches on when GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET are set — the avatar field is mapped to the Prisma schema so social create never fails.
Cookie sessions
Sessions are cookie-based end to end. The client sends credentials with withCredentials — no bearer tokens in localStorage.
Configuration reference
Environment variables
BETTER_AUTH_SECRETrequiredmin 32 chars
BETTER_AUTH_URLrequiredthe server’s own URL
CORS_ORIGINSrequiredtrusted browser origins
GOOGLE_CLIENT_IDoptionalenables Google OAuth
GOOGLE_CLIENT_SECREToptional
Where it lives
apps/server/src/modules/iam/infrastructure/auth/better-auth.adapter.tsapps/server/src/modules/iam/application/ports/auth-provider.ts
Don’t let your agent write auth from scratch.
Start with 2FA, passkeys, magic links and OAuth already wired behind a typed port — the part a blank repo ships broken.