Authentication is handled via Better Auth. Every request to a protected route must include a valid session cookie or bearer token.
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.
Connect GitHub or Google from Settings → Account to enable social sign-in. You can link multiple providers to a single account.
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');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
}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.