Hype StackHypeStack

Authentication

Authentication arrives with a SaaS starter pack. The free template has no login. Pick exactly one starter:

This page is the architecture. Credential setup stays on the pack pages.

Where auth lives

ConcernTypical path after install
Auth middlewareapps/backend/src/middleware/auth/auth-middleware.ts
Authenticated app helperapps/backend/src/utils/auth/auth-hono.ts (getAuthenticatedApp())
Auth HTTP routesapps/backend/src/routes/auth/
Permissions middlewareapps/backend/src/middleware/permissions/has-access.ts
Ability builderapps/backend/src/libs/permissions/permissions.ts
Private frontend layoutapps/frontend/src/routes/(private)/route.tsx
Onboarding layoutapps/frontend/src/routes/onboarding/route.tsx
Post-auth redirect helperapps/frontend/src/features/auth/utils/post-auth-redirect.ts

WorkOS keeps session state in a sealed cookie (wos-session). Better Auth mounts its handler under /api/auth/* and reads the session through auth.api.getSession.

Sign-in flow (Better Auth)

Email or social sign-in

  1. Browser submits credentials

    The frontend auth forms call the Better Auth client or the pack's /auth routes.

  2. Better Auth handler

    Requests under /api/auth/* hit the betterAuth() config in apps/backend/src/libs/auth/auth.ts.

  3. Session + user records

    Better Auth creates or updates the user and session (organization plugin enabled in the starter).

  4. Optional transactional email

    Password reset and verification emails go out through Resend when RESEND_API_KEY is set.

    See Mailing
  5. Redirect into the app

    Users without an organization land on /onboarding. Everyone else goes to /.

WorkOS follows the same product shape (login → session cookie → onboarding or app), but identity and memberships are resolved through the WorkOS API instead of local Better Auth tables. Google OAuth callback URLs differ per provider; set them on the pack setup page.

Protected API requests

Authenticated routers use getAuthenticatedApp(), which runs withAuthUser first. That middleware:

  1. Resolves the current user from the session
  2. Resolves organization membership and permissions for the active org
  3. Builds a CASL ability and stores user, organizationId, and ability on the Hono context

Routes then gate actions with:

ts
hasAccess({ action: "read", subject: "project" });

hasAccess requires a user, an organizationId, and ability.can(action, subject). Presets ship in the enums package (admin gets manage:all; member gets a narrower set). See Organizations.

Frontend route protection

LayoutBehavior
(private)Loads sdk.users.me. Unauthenticated users go to /login. Users with no organization go to /onboarding.
onboardingReverse guard: if the user already has an organization, leave onboarding.
Admin (private)Separate admin app login; requires an admin role or SUPER_ADMIN_EMAIL.

Side effects to remember

  • Auth changes can trigger email (verification, password reset, invitations). See Mailing.
  • Wrong FRONTEND_URL, BETTER_AUTH_URL, or WorkOS redirect URLs break callbacks. See Troubleshooting.
  • The admin app uses the same identity providers with a separate allowlist.
Sponsor open source

Every purchase and sponsorship funds my 8+ years of work on open source given freely to the community. It keeps the lights on, funds new packs, and keeps the ecosystem alive. Even a small tier means a lot. Thank you!

Sponsor on GitHub