Skip to main content
Home›Docs›Security & Compliance›Access control
Security & Compliance

Access control

Authentication, authorization, and access control matrix for Perceive8 users, keys, and agents.

Access control

Version: 1.0
Last Reviewed: 2026-03-07
Review Cadence: Quarterly
Classification: Internal / Customer-Shareable
Owner: Perceive8 Engineering & Security


Table of Contents

  1. Overview
  2. Authentication Methods
  3. Authorization Model
  4. API Key Lifecycle
  5. Session Management
  6. Admin Access Controls
  7. WebSocket & Streaming Access Controls
  8. Third-Party Access
  9. Access Control Matrix
  10. Principle of Least Privilege
  11. Known Limitations & Planned Improvements

Overview

Perceive8 implements a layered access control model combining multiple authentication methods with role-based, ownership-based, and scope-based authorization. The model follows the principle of least privilege: every identity receives only the minimum permissions required for its intended use case.

Access Control Layers

┌─────────────────────────────────────────────┐
│  Kong API Gateway (Rate Limiting, Routing)  │
├─────────────────────────────────────────────┤
│  Authentication Layer (JWT / API Key / OAuth)│
├─────────────────────────────────────────────┤
│  Authorization Layer (Role + Ownership +     │
│  Scope Enforcement)                          │
├─────────────────────────────────────────────┤
│  Row-Level Security (Supabase/PostgreSQL)    │
└─────────────────────────────────────────────┘

Every request passes through all layers. A failure at any layer results in request rejection.


Authentication Methods

1. JWT Bearer Tokens

Use Case: Dashboard users, browser-based sessions, UI-only endpoints.

Property Value
Issuer Supabase Auth
Algorithm HS256 (HMAC-SHA256)
Audience authenticated
Transport Authorization: Bearer <token> header
Expiry Enforced; expired tokens are rejected
Refresh Handled by Supabase Auth client SDK
Validation Signature verification, audience check, expiry check

Authentication Flow:

  1. User authenticates via Supabase Auth (email/password, OAuth provider, magic link).
  2. Supabase issues a JWT with sub (user ID), aud (authenticated), and exp claims.
  3. Client includes the JWT in the Authorization: Bearer header on every request.
  4. The API validates the JWT signature using the shared secret, checks the aud claim, and verifies the token has not expired.
  5. The sub claim is extracted as the authenticated user ID for downstream authorization.

UI-Only Endpoints:

Some endpoints are restricted to JWT authentication only (no API keys) using the verify_jwt_only dependency. This is used for endpoints that should only be accessible from the Perceive8 dashboard, not from programmatic integrations.

2. API Keys

Use Case: Server-to-server integrations, SDK usage, programmatic access.

Property Value
Format pk_live_<random> (prefix-based)
Storage bcrypt hash (cost=12); plaintext never stored
Lookup Prefix-based database lookup, then bcrypt verification
Transport Authorization: Bearer pk_live_... header
Expiry Optional expires_at field; enforced if set
Scopes Per-key scope list restricting permitted operations
Rate Limiting Per-key rate_limit_rpm (requests per minute)
Tracking last_used_at updated on every use

Authentication Flow:

  1. User creates an API key via the dashboard or API. The plaintext key is returned once and never stored.
  2. The key prefix (pk_live_<first-N-chars>) and bcrypt hash are stored in the database.
  3. On each request, the API extracts the prefix from the provided key, looks up the matching record, and verifies the full key against the stored bcrypt hash.
  4. If the key has an expires_at value and it has passed, the request is rejected.
  5. The key's scopes are loaded for downstream authorization checks.
  6. last_used_at is updated to the current timestamp.

3. OAuth Client Credentials

Use Case: Third-party application integrations.

Property Value
Status Alpha
Grant Type Client Credentials (client_credentials)
Client Secret bcrypt-hashed; plaintext shown once at creation
Token Type JWT
Scope Defined per OAuth client

Authentication Flow:

  1. Developer registers an OAuth client via the API, receiving a client_id and client_secret.
  2. The client exchanges credentials at the token endpoint for a JWT access token.
  3. The access token is used in the Authorization: Bearer header for subsequent requests.

Note: OAuth Client Credentials is in Alpha status. The implementation is functional but may change before GA.

4. Query Parameter Tokens

Use Case: SSE/EventSource endpoints where Authorization headers cannot be set.

Property Value
Transport ?token=<jwt> query parameter
Scope SSE/EventSource streaming endpoints only
Validation Same JWT validation as Bearer token

This method exists because the browser EventSource API does not support custom headers. The token is validated identically to a Bearer JWT.


Authorization Model

Role-Based Access Control (RBAC)

Perceive8 implements a two-tier role model:

Role Assignment Capabilities
Regular User Default for all authenticated users CRUD on own resources, API key management, webhook configuration, streaming
Admin Explicit allowlist configuration All regular user capabilities + admin dashboard, user management, system configuration, platform analytics

Admin status is determined by checking the authenticated user's ID against a configured admin allowlist. This is enforced by authorization middleware on admin-only endpoints.

Resource Ownership

Every data resource in Perceive8 is associated with an owner (the user who created it). Ownership is verified on every resource access:

Resource Ownership Field Verification
Conversations user_id Authenticated user ID must match user_id
Analyses user_id (via conversation) Ownership verified through parent conversation
Transcripts user_id (via conversation) Ownership verified through parent conversation
API Keys user_id User can only manage their own keys
Webhooks user_id User can only manage their own webhooks
OAuth Clients user_id User can only manage their own clients
Streaming Sessions user_id User can only access their own streams
Scenarios user_id User can only manage their own scenarios
Reports user_id User can only access their own reports
Speakers / Voiceprints user_id User can only manage their own speakers
Alerts user_id User can only manage their own alerts
Billing / Subscriptions user_id User can only view their own billing data

Admin Override: Admin users can access resources across all users through admin-specific endpoints (e.g., /admin/users, /admin/conversations).

Scope-Based Access Control

API keys carry a list of scopes that restrict which operations they can perform. Scopes are enforced by the require_scope() dependency on protected endpoints.

Scope Permits
conversations:read List and retrieve conversations, transcripts, analyses
conversations:write Create, update, delete conversations; upload audio
streaming:read Read streaming session data
streaming:write Create and manage streaming sessions
webhooks:read List and retrieve webhook configurations
webhooks:write Create, update, delete webhooks
scenarios:read List and retrieve scenarios
scenarios:write Create, update, delete scenarios
reports:read List and retrieve reports
reports:write Generate reports
speakers:read List and retrieve speaker profiles
speakers:write Create, update, delete speaker profiles
alerts:read List and retrieve alerts
alerts:write Create, update, delete alerts
billing:read View billing and subscription information
admin:* Full admin access (admin users only)

Scope Enforcement:

  • If an API key does not include a required scope, the request is rejected with 403 Forbidden.
  • JWT-authenticated users (dashboard) are not subject to scope restrictions — scopes apply only to API keys.
  • Scopes are set at key creation time and cannot be modified after creation (a new key must be created).

Row-Level Security (RLS)

Supabase PostgreSQL enforces Row-Level Security policies at the database layer:

  • RLS policies ensure that database queries only return rows belonging to the authenticated user.
  • This provides defense-in-depth: even if application-level ownership checks were bypassed, the database would still enforce access boundaries.
  • RLS policies are defined per table and enforced on all SELECT, INSERT, UPDATE, and DELETE operations.

API Key Lifecycle

Creation

User Request → API validates user identity → Generate random key →
Compute bcrypt hash → Store hash + prefix + metadata → Return plaintext key (once)
Step Details
Generation Cryptographically random key with pk_live_ prefix
Hashing bcrypt with cost factor 12
Storage Hash, prefix, user_id, scopes, rate_limit_rpm, expires_at
Response Plaintext key returned once; user must store it securely

Usage

Check Action on Failure
Prefix lookup 401 Unauthorized — key not found
bcrypt verification 401 Unauthorized — invalid key
Expiry check (expires_at) 401 Unauthorized — key expired
Scope check (require_scope()) 403 Forbidden — insufficient scope
Rate limit check (rate_limit_rpm) 429 Too Many Requests
last_used_at update Logged; does not block request

Expiry

  • API keys may optionally have an expires_at timestamp.
  • If set, the key is rejected after the expiry time.
  • Expired keys remain in the database but are non-functional.

Revocation

  • Users can delete their API keys through the dashboard or API.
  • Deletion removes the key record from the database.
  • Deleted keys are immediately non-functional (next request will fail prefix lookup).

Rotation (Current Limitation)

There is currently no automated key rotation workflow. To rotate a key:

  1. Create a new API key with the desired scopes.
  2. Update the integration to use the new key.
  3. Delete the old key.

This is a manual process. Automated rotation is on the roadmap. See Planned Improvements.


Session Management

JWT Session Lifecycle

Phase Details
Creation User authenticates via Supabase Auth; JWT issued
Duration Determined by Supabase Auth configuration
Refresh Supabase client SDK handles token refresh automatically
Expiry JWT exp claim enforced on every request
Revocation ⚠️ Not currently supported — JWTs are valid until expiry

Session Security

Control Status
Token expiry enforcement ✅ Implemented
Audience validation ✅ Implemented (authenticated)
Signature verification ✅ Implemented (HS256)
Session revocation ❌ Not implemented
MFA enforcement ❌ Not implemented
Concurrent session limits ❌ Not implemented (WebSocket streams are limited)

Known Limitations

  • No session revocation: Once a JWT is issued, it cannot be revoked before its natural expiry. If a user's account is compromised, the attacker's token remains valid until it expires.
  • No MFA: Multi-factor authentication is not currently enforced. Supabase Auth supports MFA, but it is not required by the application.
  • No session listing: Users cannot view or manage their active sessions.

Admin Access Controls

Who Can Be Admin

Admin status is controlled by the ADMIN_USER_IDS environment variable, which contains a comma-separated list of Supabase user IDs. This is set at deployment time and requires a redeployment to change.

Property Value
Assignment Environment variable (ADMIN_USER_IDS)
Format Comma-separated Supabase user UUIDs
Modification Requires environment variable update + redeployment
Verification verify_admin dependency checks user ID against list

What Admins Can Do

Admin endpoints (under /admin) provide:

Capability Endpoint Pattern Details
View all users GET /admin/users List all platform users
View any conversation GET /admin/conversations Access conversations across all users
Platform analytics GET /admin/analytics Usage statistics, platform metrics
System configuration Various /admin/* Platform-level settings
User management Various /admin/users/* View user details and activity

Admin Audit Gap

⚠️ Known Gap: Admin route access is not currently covered by the audit logging middleware. Admin actions are not recorded in the audit log. This is a planned improvement.


WebSocket & Streaming Access Controls

Authentication

WebSocket and streaming endpoints require the same authentication as REST endpoints:

  • JWT Bearer token in the initial HTTP upgrade request, or
  • API key with streaming:write scope.

Authorization

Control Details
Authentication Required for WebSocket upgrade
Ownership Users can only access their own streams
Concurrent Limits Per-user maximum concurrent WebSocket streams
Scope streaming:read / streaming:write for API key access

Rate Limiting

  • WebSocket connections are subject to per-user concurrent connection limits.
  • This prevents resource exhaustion from a single user opening excessive streams.

Third-Party Access

OAuth Clients

Third-party applications can integrate with Perceive8 via OAuth Client Credentials:

Property Details
Registration Via API; returns client_id and client_secret
Secret Storage bcrypt-hashed
Token Issuance Client credentials exchange for JWT
Scope Defined per client at registration
Status Alpha

Webhook Delivery

Perceive8 delivers webhook events to customer-configured endpoints:

Security Control Details
HMAC-SHA256 Signing Every payload is signed; recipients should verify
Domain Verification DNS TXT record verification before delivery
TLS Enforcement Webhooks delivered only over HTTPS
Retry Policy Failed deliveries are retried with backoff

See Webhooks Documentation for integration details.


Access Control Matrix

By Authentication Method

Endpoint Category JWT (Dashboard) API Key OAuth Client Query Param Token
Conversations CRUD ✅ ✅ (scoped) ✅ (scoped) ❌
Audio Upload ✅ ✅ (scoped) ✅ (scoped) ❌
Analysis Results ✅ ✅ (scoped) ✅ (scoped) ❌
Streaming (WebSocket) ✅ ✅ (scoped) ❌ ❌
SSE/EventSource ✅ ❌ ❌ ✅
API Key Management ✅ ❌ ❌ ❌
Webhook Management ✅ ✅ (scoped) ❌ ❌
OAuth Client Management ✅ ❌ ❌ ❌
Billing / Subscription ✅ ✅ (scoped) ❌ ❌
Scenarios ✅ ✅ (scoped) ✅ (scoped) ❌
Reports ✅ ✅ (scoped) ✅ (scoped) ❌
Speakers / Voiceprints ✅ ✅ (scoped) ❌ ❌
Alerts ✅ ✅ (scoped) ❌ ❌
Admin Endpoints ✅ (admin only) ❌ ❌ ❌
Health Check Public Public Public Public

By Role

Capability Regular User Admin
Own resource CRUD ✅ ✅
Cross-user resource access ❌ ✅
API key management (own) ✅ ✅
Webhook management (own) ✅ ✅
Platform analytics ❌ ✅
User management ❌ ✅
System configuration ❌ ✅

Principle of Least Privilege

Perceive8 implements least privilege through several mechanisms:

1. Default Deny

  • All endpoints require authentication by default.
  • Only explicitly public endpoints (health check) are accessible without credentials.
  • API keys without the required scope are denied access.

2. Scoped API Keys

  • API keys are created with specific scopes.
  • A key created for webhook management cannot access conversation data.
  • Customers are encouraged to create purpose-specific keys with minimal scopes.

3. Resource Isolation

  • Users can only access their own resources.
  • No cross-user data access is possible through regular user endpoints.
  • Database-level RLS provides a second enforcement layer.

4. Admin Restriction

  • Admin capabilities are restricted to an explicit allowlist.
  • Admin status cannot be self-assigned.
  • Admin endpoints are separated from regular user endpoints.

5. Time-Limited Access

  • JWT tokens expire and must be refreshed.
  • API keys can be created with expiry dates.
  • Temporary access can be granted via short-lived API keys.

Known Limitations & Planned Improvements

Current Limitations

Limitation Risk Current Mitigation Planned Resolution
No MFA enforcement Medium Strong password requirements via Supabase Auth Enable MFA support and enforcement (Q2 2026)
No session revocation Medium JWT expiry limits exposure window Implement token blocklist or short-lived tokens (Q3 2026)
No API key rotation workflow Medium Manual rotation possible (create new, delete old) Automated rotation with overlap period (Q2 2026)
Admin routes not audited Medium Admin access restricted to allowlist Extend audit middleware to admin routes (Q2 2026)
No distributed rate limiting Low In-memory rate limiting functional for single-instance Implement Redis-based distributed rate limiting (Q3 2026)
Scopes immutable after creation Low Create new key with desired scopes Implement scope modification API (Q3 2026)
No session listing/management Low JWT expiry limits session lifetime Implement session management UI (Q4 2026)
OAuth Client Credentials in Alpha Low Functional but API may change Stabilize and release GA (Q3 2026)
Admin assignment via env var only Low Requires deployment access to modify Implement admin management UI (Q4 2026)

Improvement Roadmap

Q2 2026

  • MFA support and optional enforcement
  • API key rotation workflow with overlap period
  • Audit logging for admin routes
  • API key usage analytics dashboard

Q3 2026

  • Session revocation mechanism (token blocklist)
  • Distributed rate limiting via Redis
  • OAuth Client Credentials GA release
  • Scope modification for existing API keys
  • IP allowlisting for API keys

Q4 2026

  • Session management UI (view/revoke active sessions)
  • Admin management UI (replace env var approach)
  • Fine-grained RBAC (custom roles beyond admin/user)
  • API key usage alerts and anomaly detection

Related Documents

Document Description
Security Overview Customer-facing security summary
Encryption Encryption standards and key management
Incident Response Plan Security incident procedures
Data Inventory Data flow documentation
Consent Model User consent and data processing basis
GDPR Readiness GDPR compliance assessment (coming soon)
DPA Template Data Processing Agreement (contact support)

Document History

Version Date Author Changes
1.0 2026-03-07 Perceive8 Engineering Initial release

This document is reviewed quarterly. Next scheduled review: 2026-06-07.