Authentication and Permissions
Source: equa-server/modules/auth/src/
Authentication Methods
Equa supports three authentication methods, all resulting in a server-side session.1. Password Login
Source:equa-server/modules/auth/src/authentication.ts
- Password hashing:
bcryptjs(10 rounds) - Two-factor authentication: Supported via
twoFactorToken - Email verification: Required before login
- Temporary passwords: Supported via
checkTempPassword() - On success:
session.user = result.user.id(line 72)
2. Google OAuth
Source:equa-server/modules/auth/src/google-auth.ts, equa-server/modules/api/src/server.ts
- Supports both ID tokens and access tokens
- Validates email verification status
- Checks audience (
aud) matches client ID - Validates
g_csrf_tokencookie/body consistency in API middleware before Google auth endpoint execution - Auto-registration: Creates user if email not found (random password assigned)
- On success:
session.user = user.id(line 88)
3. Magic Links
Source:equa-server/modules/auth/src/magic-link.ts
Note:magic-link.tsis currently an untracked file in the equa-server repo. It imports aMagicLinksentity frompersistencethat has not yet been added toschema.ts. This feature is in development but not yet integrated into the database schema.
| Property | Value |
|---|---|
| Token | 32-byte random hex |
| Expiry | 15 minutes (MAGIC_LINK_EXPIRY_MINUTES) |
| Anti-enumeration | Generates token even if user doesn’t exist |
| Dev mode | Returns token in response when EMAIL_TRANSPORTER=dev |
sendMagicLink()— Creates magic link record and sends emailverifyMagicLink()— Validates token, checks expiry, marks as usedmagicLinkLogin()— Creates session after verificationcleanupExpiredMagicLinks()— Cleanup for expired links
Session Management
Source:equa-server/modules/auth/src/sessions.ts
| Property | Value |
|---|---|
| Library | express-session |
| Store | Custom TypeORMSessionStore (Sessions entity) |
| Secret | API_SESSION_SECRET env var |
| Max age | API_SESSION_MAX_AGE (default: 604,800,000ms / 7 days) |
| SameSite | lax |
| HttpOnly | true |
| Cookie secure | When SSL enabled |
| Proxy | true |
| Rolling | true (extends session on each request) |
| Resave | false |
| Save uninitialized | false |
sessions table with columns: id, expires (indexed), user (indexed), json.
Authorization Model (RBAC)
Source:equa-server/modules/auth/src/authorization.ts, equa-server/docs/cascading-permission.puml
Entities
Permission Check Flow
- Endpoint declares
requires?: PermissionCheckproperty - vineyard-lawn calls the permission check function before the handler
- Check verifies:
- User is logged in (
requireLoggedInSync()) - User has required role/permission for the target organization
- User is logged in (
- If check fails, returns 403 Forbidden
Key Authorization Functions
Source:equa-server/modules/auth/src/authorization.ts
| Function | Lines | Purpose |
|---|---|---|
requirePermissions() | 21-26 | Wraps endpoints with permission checks |
canWriteSite() | 43-47 | Checks site-level write permissions |
canReadSite() | 49-50 | Checks site-level read permissions |
defineRelationalAuthorizationEndpoints() | 33-36 | Applies permission checks to endpoint arrays |
Cascading Permission Model
Source:equa-server/docs/cascading-permission.puml
The cascading permission model supports nested organizations with permission inheritance:
- Direct permissions: User has a role directly assigned in the organization
- Indirect permissions: User inherits permissions from a parent organization
- Union: For read operations, permissions from parent and child are combined
- Intersection: For write operations, only overlapping permissions apply
Role Tables
| Table | Purpose | Key Columns |
|---|---|---|
roles | Role definitions | id, name, description, owner, isShared |
permissions | Permission definitions | id, name |
permissions_roles | Role-to-permission mapping | permission, role |
members_roles | Member-to-role assignment (org-scoped) | member, role |
organizations_roles | Organization-to-role binding | organization, role |
global_roles_users | Global role assignment | user, role (GlobalRole enum) |
Permission Enumeration
Source: Confluence KnowledgeBase — Equa App Permissions (by Christopher Johnson)
Organization Permissions (15)
| Permission | Description |
|---|---|
| View Organization | View organization details and dashboard |
| View Cap Table | View capitalization table, shareholdings, securities |
| View Governing Documents | View agreements, operating agreements |
| View Members | View team member list and details |
| View Self | View own holdings and member page (may be deprecated) |
| View Documents | View data room documents |
| View Incentive Plan | View ESOP plans, option pools, vesting schedules |
| Edit Members | Add, invite, modify, remove team members |
| Edit Documents | Upload, modify, delete data room documents |
| Edit Organization Details | Modify organization settings, securities, legends |
| Edit Cap Table | Create/modify shareholdings, transfers, certificates |
| Edit Incentive Plan | Create/modify ESOP plans, pools, grant options |
| Delete Documents | Remove documents from data rooms |
| Signing | Digital signature capability for agreements |
| Edit Billing | Manage subscriptions, payment profiles, billing |
Site Permissions (2, for site admins only)
| Permission | Description |
|---|---|
| Write Site | Full site-level write access (admin operations) |
| Read Site | Full site-level read access (admin view all organizations) |
requirePermissions()— generic permission checkcanWriteSite()/canReadSite()— site-level admin accesscanEditCapTable,canViewOrganization,canEditMembers,canEditOrganizationBilling, etc. — organization-level checks used in endpoint definitions
Security Notes
- No explicit rate limiting middleware found in the codebase
- Registration IP limit:
REGISTRATION_IP_LIMIT(default: 20; applied inmodules/referral/src/referral.ts) - Domain blacklist:
domain_blackliststable - Email blacklist:
email_blackliststable - Email verification required before login
- Two-factor authentication supported but optional