Repository navigation
Local & Workspace Authentication Integration
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Security Considerations
- Conclusion
This document provides comprehensive documentation for the local and workspace-based authentication system in PersonalLearningPro. It replaces the legacy Firebase implementation with a self-hosted, PostgreSQL-backed identity system designed for multi-tenancy.
The authentication system is organized across three primary layers:
- Server-side Logic: Token hashing, permission mapping, and database queries.
- API Layer: Endpoints for signup, login, session refresh, and logout.
- Frontend Integration: React context for state management and cookie-based session handling.
graph TB
subgraph "Frontend"
Ctx["AuthProvider<br/>(React Context)"]
UI["Auth Dialogs"]
end
subgraph "Backend API"
AuthRoutes["Auth Routes<br/>(auth.ts)"]
MW["Auth Middleware"]
end
subgraph "Data Layer"
AuthLib["Auth Lib<br/>(auth-workspace.ts)"]
PG["PostgreSQL<br/>(pg-queries.ts)"]
end
Ctx --> AuthRoutes
AuthRoutes --> AuthLib
AuthRoutes --> PG
MW --> AuthLib
Every user belongs to at least one workspace. Upon signup, a user creates their first workspace and is automatically assigned the "Owner" role.
Sessions are managed via two HttpOnly cookies:
-
access_token: A short-lived (15m) JWT used for authenticating individual requests. -
refresh_token: A long-lived (30d) opaque token stored in the database for regenerating access tokens.
Permissions are derived from the user's active workspace membership. The permissionsForWorkspaceRole function in auth-workspace.ts defines the mapping between roles and permission strings.
The system implements a stateless-statful hybrid model:
- Stateless: The access token contains all info needed to verify a request without a database hit.
- Stateful: The refresh token requires a database lookup to ensure the session is still valid and not revoked.
sequenceDiagram
participant User as "User"
participant API as "Auth API"
participant DB as "PostgreSQL"
User->>API : "POST /api/auth/login"
API->>DB : "Verify Credentials"
DB-->>API : "Success"
API->>DB : "Store Session (Refresh Token)"
API-->>User : "Set Cookies (Access + Refresh)"
Note over User, API : 15 Minutes Later...
User->>API : "POST /api/auth/refresh"
API->>DB : "Verify Refresh Token"
DB-->>API : "Valid"
API->>API : "Rotate Refresh Token"
API-->>User : "Set New Cookies"
Signup is a multi-step relational operation:
- Create a
Userrecord with a hashed password (Bcrypt). - Create a
Workspacewith a unique slug. - Create a
WorkspaceMembershiplinking the user to the workspace asowner. - Issue initial session tokens.
- An admin creates a
workspace_inviterecord with a SHA-256 hashed token. - The user receives an email with a unique link.
- Upon acceptance, the user sets their password, and a membership is created.
-
Password Hashing: Uses
bcryptjswith 12 salt rounds. -
Cookie Security:
HttpOnly,Secure(in production), andSameSite=Lax. - Token Rotation: Refresh tokens are rotated on every use to prevent replay attacks.
- Hashed Tokens: All invitation and reset tokens are hashed in the database.
The transition to local workspace-based authentication provides the platform with greater control over data sovereignty, multi-tenant logic, and security workflows. By removing the external dependency on Firebase, we have achieved a more integrated and performant identity solution.