Hype StackHypeStack

SaaS Starter (Better Auth)

Authentication, organizations, roles, sessions, feature flags, and an admin app, powered by Better Auth on your own Postgres. This is the starter-saas-betterauth pack, and the default starter. Unlike WorkOS, Better Auth is a self-hosted library, so there's no separate account to create. You bring your own Google OAuth app.

bash
npx @hype-stack/cli compose --packs starter-saas-betterauth,layout-basic

What you get

  • Email/password and Google sign-in, password reset, email verification
  • Organizations: create, switch, invite members by email, roles and CASL permissions enforced with hasAccess
  • An onboarding flow for users with no organization yet
  • Per-organization feature flags, with an admin tab to override them
  • A settings page with profile and organization tabs that feature packs extend
  • The full admin app: users, organizations, dashboard rows, admin management
  • Mobile and browser-extension slots with the auth screens, the organization switcher, and settings
  • The organization switcher and menu are contributed to the layout's shell action areas, so they render in every layout

Starting from the free auth starter instead? Swapping to this one later is a family swap with no migration.

For session flow, middleware, and route guards, see Authentication and Organizations.

What you need

  • A Google OAuth web app you create in Google Cloud Console. Better Auth talks to Google directly.
  • Resend for transactional email (password reset, email verification). Uses the base template's RESEND_API_KEY.
  • Postgres and Valkey (base services).

Register a Google OAuth app

  1. Open Google Cloud Console > APIs & Services > Credentials.
  2. Create an OAuth 2.0 Client ID of type Web application.
  3. Under Authorized redirect URIs, add the Better Auth callback path:
http://localhost:3000/api/auth/callback/google
  1. Copy the Client ID and Client secret into apps/backend/.env as GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.

In production, add your deployed origin as well:

https://yourdomain.com/api/auth/callback/google

The path is fixed: Better Auth owns the handler at /api/auth/*, and the Google callback is always /api/auth/callback/google appended to your BETTER_AUTH_URL.

Environment variables

VariablePurpose
BETTER_AUTH_URLOrigin Better Auth runs on (e.g. http://localhost:3000)
BETTER_AUTH_SECRETAuth secret. The CLI generates one at install time
GOOGLE_CLIENT_IDGoogle OAuth client ID
GOOGLE_CLIENT_SECRETGoogle OAuth client secret
MOBILE_OAUTH_REDIRECT_URLDeep link the Expo app returns to after Google sign-in (default hypestack://callback)
RESEND_API_KEYTransactional email (password reset, verification)
SUPER_ADMIN_EMAILBootstrap admin emails for the admin app

Google sign-in flow

The pack starts Google sign-in from GET /auth/google/:intent, which calls Better Auth's signInSocial. After Google redirects back to /api/auth/callback/google, Better Auth exchanges the code, creates the session, and sends the browser to / (or /onboarding if the user has no organization).

Admin app

This starter also ships a separate admin app for managing users and organizations. Set SUPER_ADMIN_EMAIL in apps/backend/.env to sign in the first time.