Skip to content

Auth System

Authentication is handled by better-auth, a session-based auth library. There are no JWT tokens — authentication state lives in a server-side session tied to a cookie.

Session flow

  1. User clicks "Sign in with Google"
  2. Browser redirects to /api/auth/signin/google
  3. better-auth redirects to Google's OAuth consent screen
  4. Google redirects back to /api/auth/callback/google
  5. better-auth creates or updates a User, Account, and Session record in the database
  6. A session cookie (better-auth.session_token) is set on the browser
  7. Every subsequent request sends the cookie automatically

Routes

better-auth mounts its routes under /api/auth/. Key endpoints:

EndpointDescription
GET /api/auth/signin/googleInitiate Google OAuth flow
GET /api/auth/callback/googleOAuth callback (handled by better-auth)
POST /api/auth/signoutInvalidate the current session
GET /api/auth/sessionReturn the current session and user

Guards and decorators

AuthGuard (global)

Applied globally in AppModule. Validates the session cookie and attaches the User object to request.user. Returns 401 if no valid session exists.

@Public()

Marks a route as publicly accessible (bypasses AuthGuard):

typescript
import { Public } from '../auth/decorators'

@Public()
@Get('health')
health() { return 'ok' }

@CurrentUser()

Injects the authenticated User object:

typescript
@Get('me')
getProfile(@CurrentUser() user: User) {
  return user
}

@TenantId()

Extracts tenantId from request.params.tenantId (set by TenantGuard):

typescript
@Get()
findAll(@TenantId() tenantId: string) { ... }

@TenantUserId()

Injects the tenantUserId resolved by TenantGuard for the current user within the requested tenant.

API Key authentication

Requests can also authenticate with an API key in the Authorization header:

Authorization: Bearer tt_<key>

The ApiKeyGuard (applied globally alongside AuthGuard) recognises this prefix, hashes the key, and looks it up in the api_keys table. If valid and not revoked/expired, it grants admin-level access to the key's tenant.

Database tables

better-auth manages these tables automatically (do not modify them manually):

  • users — Global user accounts
  • sessions — Active sessions
  • accounts — OAuth provider links (Google)
  • verifications — Email verification tokens

TT Time Tracker — Internal Documentation