Access Controls
Last updated: March 2026
This document describes HAIEC's authentication methods, role hierarchy, organization membership model, API key management, and the three-layer authorization architecture that enforces tenant isolation.
1. Authentication Methods
- OAuth 2.0 via GitHub — Primary authentication provider (NextAuth.js
GitHubProvider). - OAuth 2.0 via Google — Secondary authentication provider (NextAuth.js
GoogleProvider). - Credentials provider — Test/E2E only. Disabled in production.
Not currently offered: SAML-based SSO, LDAP, Active Directory integration, or MFA enforcement at the HAIEC application level. MFA is available at the identity provider level (GitHub and Google both support TOTP, SMS, and hardware keys). We do not claim to enforce MFA.
2. Session Management
- Server-side sessions: NextAuth.js with Prisma adapter. Session data stored in Neon
sessionstable. - Cookie security: HttpOnly, Secure flags set. Session token not accessible to client-side JavaScript.
- JWT claims: Session JWT includes
userId,email,role,organizationId,tier. - Automatic timeout: Sessions expire after configured inactivity period.
- No client-side session trust: All API routes re-validate session server-side via
getSafeSession()orgetServerSession(authOptions).
3. Role Hierarchy
| Role | Scope | Capabilities |
|---|---|---|
| superadmin | Platform | Full system access. Admin dashboard, user management, system monitoring. DB-validated via isSuperAdmin(). |
| admin | Platform | Limited admin access. Used for platform operations. Validated via isAdmin(). |
| owner | Organization | Organization owner. Bypasses role checks within their org. Can manage billing, invite members, delete org. |
| admin | Organization | Org admin. Can invite members, manage assessments, view evidence. |
| member | Organization | Regular org member. Can create/edit assessments, run scans. |
| viewer | Organization | Read-only org member. Can view dashboards and reports but not modify. |
Platform roles (superadmin, admin) are stored in the users.role field. Organization roles (owner, admin, member, viewer) are stored in the organization_members.role field.
4. Organization Membership
Users belong to organizations through the organization_members table:
- Fields:
userId,organizationId,role,status - Status values:
active,invited,removed - Per-member permissions (database fields):
canEditAssessmentscanInviteMemberscanManageBillingcanViewEvidence
- Computed permissions:
canDeleteOrg— computed at runtime asisOwner(only organization owners can delete). Not a database field.
Only status: 'active' memberships grant access. Removed or invited (not yet accepted) memberships are rejected.
5. API Authentication
- Bearer token:
Authorization: Bearer <api-key>header. Validated viavalidateApiKey(). - X-API-Key header: Alternative key delivery for CI/CD integrations.
- HMAC-SHA256 signatures: CI/CD integrations sign requests with HMAC for non-repudiation.
- Compliance-twin API keys: Scoped to
customerId(tenant-scoped by design). Validated inlib/compliance-twin/auth.ts. - Key storage: API keys stored as hashes. Plaintext shown only once at creation. Rotatable on demand.
- Audit logging: All API key authentications logged with timestamp and IP.
6. Authorization Gates (3-Layer)
Layer 1: requireOrganizationAccess()
Used by 49 API routes. Resolves organization ID from session, query params, or body. Verifies active membership in organization_members. Returns verified organizationId for Prisma query scoping. Supports requiredRole parameter for role-based access.
Source: lib/org-context.ts
Layer 2: validateTenantContext()
Requires explicit X-Organization-Id header. Validates organization exists, is not deleted, and user is an active member. Returns TenantContext with role-based permissions. Used for operations requiring explicit tenant declaration.
Source: lib/safety/tenant-isolation.ts
Layer 3: requirePermission()
Fine-grained RBAC for specific operations. Checks permissions like canEditAssessments, canManageBilling, canViewEvidence. Used by kill-switch, compliance-twin, and platform permission systems.
Sources: lib/safety/tenant-isolation.ts, lib/platform/require-permission.ts, lib/kill-switch/services/rbac-service.ts
7. Admin Authorization
- isSuperAdmin(userId): DB-validated. Checks
users.role === 'superadmin'. No hardcoded emails. - isAdmin(userId): Checks
users.role === 'admin' || 'superadmin'. - requireSuperAdmin(userId): Throws 403 error if not superadmin. Used by admin-only API routes.
- Admin audit logging: All admin actions logged to
admin_audit_logstable withadminId,action,targetId,timestamp,ipAddress. Append-only (immutable via database trigger). - Credit adjustments:
validateCreditAdjustment()enforces bounds and logs all credit changes.
Source: lib/admin-auth.ts