Skip to content

Auth (Better Auth)

  • Server config: packages/auth/src/index.ts
  • Web client: apps/web/src/lib/auth-client.ts
  • Env examples:
    • apps/server/.env.example
    • .dev.vars.example
  • Better Auth expects the Turnstile token in HTTP header: x-captcha-response
  • Plugin is enabled automatically when TURNSTILE_SECRET is set on the API Worker.
  • Our web UI renders Turnstile using PUBLIC_TURNSTILE_SITE_KEY.

Protected auth endpoints (current):

  • /sign-up/email
  • /sign-in/email
  • /sign-in/social
  • /request-password-reset
  • /phone-number/send-otp
  • /phone-number/verify

Set credentials on the API Worker:

  • GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET
  • GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET
  • APPLE_CLIENT_ID, APPLE_CLIENT_SECRET

If a provider is not configured, its login will fail with a server-side error.

Better Auth uses /api/auth/callback/{provider} by default (based on BETTER_AUTH_URL).

Local redirect URIs:

  • http://localhost:3000/api/auth/callback/google
  • http://localhost:3000/api/auth/callback/github
  • http://localhost:3000/api/auth/callback/apple

Production redirect URIs:

  • https://dubbit.ai/api/auth/callback/google
  • https://dubbit.ai/api/auth/callback/github
  • https://dubbit.ai/api/auth/callback/apple
  • We support OTP-based phone flows via Better Auth phone-number plugin.
  • Phone numbers must be E.164 (example: +48600000000).
  • OTP delivery is external: we do not send SMS ourselves.

Required env:

  • PHONE_OTP_PROVIDER_URL (webhook that sends SMS/WhatsApp/etc)
  • PHONE_OTP_PROVIDER_BEARER_TOKEN (optional)

Passkeys use @better-auth/passkey.

Required env (API Worker):

  • PASSKEY_RP_ID (recommended: dubbit.ai in prod, localhost in local dev)
  • PASSKEY_RP_NAME (default: dubbit.ai)
  • PASSKEY_ORIGINS (comma-separated allowed origins, example: https://dubbit.ai,https://docs.dubbit.ai,http://localhost:5173)

Notes:

  • Passkeys require HTTPS, except localhost during development.
  • RP ID and allowed origins must match the domain where the WebAuthn ceremony happens.

We enable Better Auth two-factor plugin (TOTP + backup codes).

UI:

  • Users can enable/disable 2FA from /account.
  • Enabling returns totpURI + backupCodes and requires a follow-up verification with the authenticator code.

We enable last-login-method plugin and store:

  • cookie: better-auth.last_used_login_method
  • database field: user.last_login_method

We also resolve phone-based flows as method phone.