Logo

Authentication

Secure user sessions, roles, and permissions—pre-configured using Better Auth.

So, we're running Better Auth with a Drizzle adapter. It's a solid, production ready setup. We've got Email & Password sign in, session management, and Role Based Access Control (RBAC) ready to rock.

Pre-Built Pages

Good news: the core authentication pages are already done and integrated into the router. You don't need to build them from scratch.

  • Sign In
  • Sign Up
  • Forgot Password
  • Sign Out

They're fully functional and wired up to the authentication client, so you can focus on building the actual application.

User Auth & Sessions

The Middleware

The main guard for protected routes is the isAuthenticated middleware. It's simple:

  • It checks for a valid user and token in the session context.
  • If it fails the check, it automatically bounces the user to /sign-in (that's Links.signIn).
  • If it passes, it stuffs the user and token into the route context so your server functions can use them.

Session Helpers

All the session stuff is in src/features/auth/session.ts, which sits on top of the main session store (@/lib/session).

TaskCore Function
Get current user/tokenuseAppSession() / getSessionUserOrRedirect
Save/Update session datasaveSessionUser(data)
Clear session (Log Out)removeSessionUser()

Roles & Permissions (RBAC)

You'll mainly use the hasPermission middleware or the verifyPermission server action to check access.

  • hasPermission(permission): This is a TanStack Router middleware. It runs before the route/handler executes, checks the user's permissions, and sets an isPermitted: boolean flag in the context.
  • withPermission(context, handler): A simple wrapper. It runs a secure handler function only if context.isPermitted is true.

Look at this: Any secure server action, like getRoles, uses this pattern:

.middleware([isAuthenticated, hasPermission({user: ["read"]})])
.handler(async ({ context }) => withPermission(context, () => { /* safe action code goes here */ }))