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
Architecture Overview
Team Authentication Flow
Client Portal Authentication Flow
Database Tables
Team Auth Tables
| Table | Purpose |
|---|---|
user | Team member profiles |
session | Active team sessions |
account | OAuth provider connections |
user_preference | UI preferences |
Client Portal Auth Tables
| Table | Purpose |
|---|---|
client_user | Client portal users |
client_session | Active client sessions |
client_account | Client credentials |
client_verification | Password reset tokens |
client_user_preference | Client UI preferences |
Access Control
Team Member Access Levels
CharleOS uses a two-tier access system:Access Levels (System Permissions)
| Level | Who | Permissions |
|---|---|---|
| Admin | Luke | Full system access, all features |
| Manager | Simon, Andre, Ben, Nic | Management features, reports, admin tools |
| Staff | Everyone else | Standard access based on work type |
Work Types (Role-Based Features)
| Work Type | Dashboard | Key Features |
|---|---|---|
| development | IC Dashboard | My Tasks, My Schedule, Time Tracking |
| design | IC Dashboard | My Tasks, My Schedule, Time Tracking |
| qa | IC Dashboard | My Tasks, My Schedule, Time Tracking |
| pm | PM Dashboard | Task scheduling, client blocks |
| csm | CSM Dashboard | Quotes, clients, help desk |
| sdr | Staff Dashboard | Limited access |
accessLevelcontrols what management features you seeworkTypecontrols which dashboard and features you get- Example: A
developerwithmanageraccess level sees the Manager Dashboard (not IC Dashboard)
Client Portal Access
Client users have simpler access control:| Role | Permissions |
|---|---|
| admin | Can manage other client users, approve quotes |
| member | Can view tasks, submit tickets, view quotes |
Authentication Features
Team Authentication
Google OAuth
Google OAuth
- Only authentication method (no password)
- Must use @charle.co.uk email
- Profile picture synced from Google
- Auto-uploaded to Cloudflare R2
Invite-Only System
Invite-Only System
- No public signup page
- Admin creates user accounts
- Invitation email sent
- User signs in with Google
Session Management
Session Management
- 7-day session expiry
- Automatically refreshed on activity
- Stored in PostgreSQL
- Tracks IP and user agent
Pending Approval Screen
Pending Approval Screen
- 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
Email/Password
Email/Password
- Password-based authentication
- Passwords hashed with bcrypt
- Password reset via email token
- No Google OAuth
Invitation Workflow
Invitation Workflow
- CSM creates client user
- Invitation email sent with token
- Client sets password on first login
- Token expires after 7 days
Per-Client Isolation
Per-Client Isolation
- Users belong to one client
- Can only see their client’s data
- No cross-client access
- Enforced at database level
Environment Variables
Team Auth
| Variable | Description |
|---|---|
BETTER_AUTH_SECRET | Secret for encrypting sessions (32+ chars) |
BETTER_AUTH_URL | Base URL (http://localhost:3000 local, https://charle.agency prod) |
NEXT_PUBLIC_BETTER_AUTH_URL | Public-facing auth URL (client-side) |
GOOGLE_CLIENT_ID | Google OAuth client ID |
GOOGLE_CLIENT_SECRET | Google OAuth client secret |
Client Portal Auth
Uses the same Better Auth instance but with client-specific context:| Variable | Description |
|---|---|
NEXT_PUBLIC_CLIENT_PORTAL_URL | Client portal URL (http://clients.localhost:3000 local, https://clients.charle.agency prod) |
Code Structure
Team Auth
Client Portal Auth
Security Features
CSRF Protection
CSRF Protection
Better Auth includes built-in CSRF protection for all auth requests
Session Security
Session Security
- Sessions stored server-side in PostgreSQL
- Tokens are random, not predictable
- IP address and user agent tracked
- Automatic session cleanup on expiry
Password Security (Client Portal)
Password Security (Client Portal)
- Passwords hashed with bcrypt (cost factor 10)
- Never stored in plain text
- Password reset requires email verification
- Tokens expire after 7 days
Domain Restrictions
Domain Restrictions
- Team auth: Only @charle.co.uk emails
- Client portal: Per-client isolation
- No cross-origin session sharing