Skip to main content
CharleOS uses Better Auth for authentication with separate systems for team members and clients. This page provides an overview of the auth architecture.

Two Auth Systems

CharleOS has two completely separate authentication systems:

Team Auth

Internal team members (developers, PMs, CSMs, managers)
  • Google OAuth only
  • Invite-only (no public signup)
  • Role-based access control
  • Session-based authentication

Client Portal Auth

Client employees accessing the client portal
  • Email/password authentication
  • Invitation workflow
  • Per-client access control
  • Separate database tables
These systems are completely isolated. A team member cannot log into the client portal with their team credentials, and vice versa.

Architecture Overview

Team Authentication Flow

Client Portal Authentication Flow

Database Tables

Team Auth Tables

Client Portal Auth Tables

Access Control

Team Member Access Levels

CharleOS uses a two-tier access system:

Access Levels (System Permissions)

Work Types (Role-Based Features)

Combined Logic:
  • accessLevel controls what management features you see
  • workType controls which dashboard and features you get
  • Example: A developer with manager access level sees the Manager Dashboard (not IC Dashboard)

Client Portal Access

Client users have simpler access control:

Authentication Features

Team Authentication

  • Only authentication method (no password)
  • Must use @charle.co.uk email
  • Profile picture synced from Google
  • Auto-uploaded to Cloudflare R2
  • No public signup page
  • Admin creates user accounts
  • Invitation email sent
  • User signs in with Google
  • 7-day session expiry
  • Automatically refreshed on activity
  • Stored in PostgreSQL
  • Tracks IP and user agent
  • New users start as “pending”
  • See waiting screen until admin assigns role
  • Prevents access to app features
  • Admin updates status to “active”

Client Portal Authentication

  • Password-based authentication
  • Passwords hashed with bcrypt
  • Password reset via email token
  • No Google OAuth
  • CSM creates client user
  • Invitation email sent with token
  • Client sets password on first login
  • Token expires after 7 days
  • Users belong to one client
  • Can only see their client’s data
  • No cross-client access
  • Enforced at database level

Environment Variables

Team Auth

Client Portal Auth

Uses the same Better Auth instance but with client-specific context:

Code Structure

Team Auth

Client Portal Auth

Security Features

Better Auth includes built-in CSRF protection for all auth requests
  • Sessions stored server-side in PostgreSQL
  • Tokens are random, not predictable
  • IP address and user agent tracked
  • Automatic session cleanup on expiry
  • Passwords hashed with bcrypt (cost factor 10)
  • Never stored in plain text
  • Password reset requires email verification
  • Tokens expire after 7 days
  • Team auth: Only @charle.co.uk emails
  • Client portal: Per-client isolation
  • No cross-origin session sharing

Session Management

Team Sessions

Client Portal Sessions

Common Auth Patterns

Protected Route (Server Component)

Protected API Route

Client-Side Auth Check

Better Auth

Better Auth configuration details

Permissions

Role-based access control

Sessions

Session management and lifecycle

Environment Variables

Auth environment configuration