# Authorization Model

## Two Completely Separate Authorization Systems

Supplier Pulse has two user populations with no shared auth context:

| System            | Users                      | Auth Source        | Entry Point           |
|-------------------|----------------------------|--------------------|----------------------|
| Owner Control Plane| Platform operators         | Supabase Auth      | `/owner/`            |
| Tenant Plane       | Company employees          | Supabase Auth      | `/`, `/dashboard`, etc|

Both use the same Supabase Auth service, but are distinguished by the `is_platform_owner` flag and checked at the middleware layer.

---

## Owner Portal Authorization

### Identity
Owner users are normal Supabase Auth users with `user_profiles.is_platform_owner = true`.

### Middleware Guard
The proxy middleware intercepts all `/owner/` and `/api/owner/` requests and verifies:
1. Valid Supabase session exists
2. `user_profiles.is_platform_owner = true`
3. If not: redirect to `/login?next=/owner/dashboard`

```typescript
// lib/supabase/proxy.ts — owner guard
if (pathname.startsWith('/owner') || pathname.startsWith('/api/owner')) {
  const isPlatformOwner = await checkIsPlatformOwner(supabase)
  if (!isPlatformOwner) {
    return NextResponse.redirect(new URL('/login', req.url))
  }
}
```

### Owner Roles
Fine-grained owner access is controlled by `cp_owner_users.role`:

| Role               | Tenants | Plans | Modules | Branding | Audit | Support | Destructive |
|--------------------|---------|-------|---------|----------|-------|---------|-------------|
| PLATFORM_OWNER     | ✓       | ✓     | ✓       | ✓        | ✓     | ✓       | ✓           |
| PLATFORM_ADMIN     | ✓       | ✓     | ✓       | ✓        | ✓     | ✓       | —           |
| SUPPORT_ENGINEER   | read    | —     | —       | —        | ✓     | ✓       | —           |
| BILLING_ADMIN      | read    | ✓     | —       | —        | read  | —       | —           |
| AUDITOR            | read    | read  | read    | read     | ✓     | —       | —           |

### Server-side Permission Check
```typescript
import { requireOwnerRole } from '@/lib/owner-audit/middleware'

export async function PATCH(req: NextRequest) {
  const owner = await requireOwnerRole(req, ['PLATFORM_OWNER', 'PLATFORM_ADMIN'])
  // owner.id, owner.email, owner.role available
}
```

---

## Tenant Authorization

### Existing Role Hierarchy
```
extern (0) → readonly (1) → consultant (2) → admin (3) → masteradmin (4)
```

### Permission System
Actions require explicit permission grants via `role_permissions` table:
```typescript
import { hasPermission } from '@/lib/auth/permissions-shared'
const canEdit = hasPermission(session, 'edit_project')
```

### Module-Level Permission Check
Before executing module logic, verify entitlement AND permission:
```typescript
await requireEntitlement(req, 'MODULE_OEE')           // platform check
await requirePermission(req, 'view_oee')               // tenant role check
```

---

## Support Access

Support access allows a platform engineer to read (not write) tenant data for debugging purposes.

**Requirements**:
1. Must be triggered from Owner Portal with explicit reason entered
2. Creates a `cp_support_access_sessions` record with `expires_at` (max 4 hours)
3. All queries during support session are tagged with `support_session_id`
4. Session cannot be extended — must create a new one with new reason
5. Visible in tenant's own audit log
6. Owner audit captures session creation and termination

**Implementation**:
```typescript
// Tenant API route — check support session
const supportSession = await getActiveSupportSession(tenantId, ownerUserId)
if (!supportSession) throw new UnauthorizedError()

// Log access
await logSupportAccess(supportSession.id, req.url, req.method)
```

---

## Secret Management

| Secret               | Location                      | Access                    |
|----------------------|-------------------------------|---------------------------|
| Tenant Supabase URL  | Vercel env per project        | Runtime only              |
| Tenant Supabase Keys | Vercel env per project        | Server-side only          |
| Control plane DB URL | Vercel env (owner deployment) | Owner portal server only  |
| Control plane RO key | Vercel env (tenant deployment)| Entitlement/branding reads|
| Email API key        | Vercel env                    | Server-side only          |

No secrets in code. No secrets in client-side code. No secrets logged.

---

## JWT Claims

Tenant user JWT contains:
```json
{
  "sub": "user-uuid",
  "role": "authenticated",
  "user_metadata": {
    "role": "consultant"
  }
}
```

Future (multi-tenant Supabase): will add `tenant_id` to JWT via custom claims.

Owner user JWT contains (checked via DB lookup, not JWT claim):
```json
{
  "sub": "owner-user-uuid",
  "role": "authenticated"
}
```
`is_platform_owner` is always verified from `user_profiles` DB, never trusted from JWT alone.
