Authentication

How authentication works and how to manage sessions and tokens.

Overview

Authentication is handled via Better Auth. Every request to a protected route must include a valid session cookie or bearer token.

Sign in methods

Email and password

The standard sign-in flow at /sign-in. Credentials are validated server-side and a session cookie is set on success.

Request a one-time sign-in link sent to your email. The link expires after 15 minutes.

Social providers

Connect GitHub or Google from Settings → Account to enable social sign-in. You can link multiple providers to a single account.

Session management

Sessions are stored server-side. You can view and revoke active sessions from Settings → Security.

// Check session server-side
import { auth } from '~/server/auth';

const session = await auth.api.getSession({ headers: request.headers });
if (!session) redirect('/sign-in');

Token expiry and refresh

Sessions automatically refresh on activity. Inactive sessions expire after 30 days by default. Configure this in src/server/auth/index.ts:

session: {
  expiresIn: 60 * 60 * 24 * 30, // 30 days
  updateAge: 60 * 60 * 24,       // refresh if 1 day old
}

Role-based access

Users have a role field (user or admin). Guard routes using the session role:

if (session.user.role !== 'admin') throw redirect('/a/dashboard');

Roles can be managed from the admin panel at /admin/users.