Skip to main content

API Roles & Authentication

All Torvus Platform API endpoints require authentication. This guide explains role requirements, error responses, and best practices for working with role-based access control.


Authentication Model​

Required Headers​

All API requests must include authentication:

Authorization: Bearer <supabase_access_token>
Cookie: <session_cookies>

Minimum Role​

The minimum role for all endpoints is VAULT_VIEWER, which is automatically granted to all authenticated users.


Role Requirements by Endpoint​

Vault Endpoints​

GET /api/vaults​

List all vaults owned by the current user.

Authentication: Required Minimum Role: VAULT_VIEWER (owner only)

Response:

{
"vaults": [
{
"id": "vault-123",
"name": "My Vault",
"ownerUid": "user-456",
"created_at": "2025-10-01T00:00:00Z"
}
],
"_meta": {
"role": "VAULT_VIEWER",
"canCreate": true
}
}

GET /api/vaults/[id]​

Retrieve vault details.

Authentication: Required Minimum Role: VAULT_VIEWER (owner only) or VAULT_ADMIN (any vault, future)

Error Responses:

  • 401 Unauthorized - Not authenticated
  • 403 Forbidden - VAULT_VIEWER but not owner
  • 404 Not Found - Vault does not exist

Response with Metadata:

{
"vault": {
"id": "vault-123",
"name": "My Vault",
"ownerUid": "user-456"
},
"_meta": {
"viewingAsOwner": true,
"canModify": false,
"role": "VAULT_VIEWER"
}
}

POST /api/vaults​

Create a new vault.

Authentication: Required Minimum Role: VAULT_VIEWER (any authenticated user)

Note: Creator automatically becomes VAULT_OWNER of the new vault.

Request:

{
"name": "New Vault"
}

Response:

{
"vault": {
"id": "vault-789",
"name": "New Vault",
"ownerUid": "user-456"
},
"_meta": {
"autoGrantedOwnership": true
}
}

DELETE /api/vaults/[id]​

Delete a vault permanently.

Authentication: Required Minimum Role: VAULT_OWNER (ownership required)

Error Responses:

  • 401 Unauthorized - Not authenticated
  • 403 Forbidden - VAULT_VIEWER/VAULT_OPERATOR but not VAULT_OWNER
  • 404 Not Found - Vault not found

403 Error Example:

{
"ok": false,
"error": "Insufficient permissions",
"required": ["VAULT_OWNER"],
"actual": ["VAULT_VIEWER"]
}

Document Endpoints​

POST /api/vaults/[id]/documents/initiate​

Upload a document to a vault.

Authentication: Required Minimum Role: VAULT_VIEWER (owner of vault)

Request:

{
"fileName": "document.pdf",
"fileSize": 1024000
}

GET /api/documents/[id]​

Retrieve document details.

Authentication: Required Minimum Role: VAULT_VIEWER (owner only)

DELETE /api/documents/[id]​

Delete a document.

Authentication: Required Minimum Role: VAULT_OWNER (ownership of vault required)

Release Endpoints​

POST /api/vaults/[id]/release/execute​

Execute a vault release (shadow or real).

Authentication: Required Minimum Role:

  • Shadow releases: VAULT_OPERATOR+
  • Real releases: VAULT_ADMIN+

Additional Requirements (Real Releases):

  • Multi-factor authentication (MFA) verified
  • Approval granted (if policies require)
  • Clean document scans (no threats)

Request:

{
"shadowMode": true
}

Error for Insufficient Role:

{
"ok": false,
"error": "Insufficient role",
"required": ["VAULT_ADMIN"],
"actual": ["VAULT_VIEWER"],
"requestId": "req-123"
}

Signing Endpoints​

POST /api/sign​

Sign a document with PAdES.

Authentication: Required Minimum Role: VAULT_VIEWER (any authenticated user)

Note: Document signing is available to all authenticated users.

GET /api/signing/jobs/owner​

List signing jobs owned by current user.

Authentication: Required Minimum Role: VAULT_VIEWER (own jobs only)

Audit Endpoints​

GET /api/audit-events​

List audit events for the current user.

Authentication: Required Minimum Role: VAULT_VIEWER (own events only)

Query Parameters:

  • limit - Number of events to return (default: 50)
  • offset - Pagination offset
  • action - Filter by action type

Error Responses​

401 Unauthorized​

User is not authenticated.

{
"ok": false,
"error": "Authentication required",
"requestId": "req-123"
}

Solution: Provide valid authentication credentials.

403 Forbidden​

User is authenticated but lacks required role.

{
"ok": false,
"error": "Insufficient permissions",
"required": ["VAULT_OWNER"],
"actual": ["VAULT_VIEWER"],
"requestId": "req-123"
}

Solution: Request role upgrade or contact vault owner.

404 Not Found​

Resource does not exist.

{
"ok": false,
"error": "Vault not found",
"requestId": "req-123"
}

Note: For security, 404 is returned even if the resource exists but user lacks access (to prevent information disclosure).


Role-Based Filtering​

List Endpoints​

List endpoints automatically filter by ownership:

VAULT_VIEWER:

  • Returns only owned resources
  • Cannot see other users' data

Future: VAULT_ADMIN may see all resources for operational monitoring.

Metadata Fields​

API responses include metadata for client-side role handling:

{
"_meta": {
"role": "VAULT_VIEWER", // User's primary role
"viewingAsOwner": true, // Is user the owner?
"canModify": false, // Can user modify this resource?
"requiredRoleForModify": "VAULT_OWNER"
}
}

Best Practices​

Client-Side Role Checks​

Use metadata to show/hide UI elements:

const response = await fetch('/api/vaults/123');
const data = await response.json();

if (!data._meta.canModify) {
// Disable edit/delete buttons
// Show "View-Only Mode" alert
}

Error Handling​

Handle role-based errors gracefully:

try {
await fetch('/api/vaults/123', { method: 'DELETE' });
} catch (error) {
if (error.status === 403) {
const body = await error.json();
showRoleUpgradeDialog(body.required);
}
}

Optimistic UI​

Don't show actions users cannot perform:

import { useUserRole } from '@/hooks/useUserRole';

function VaultActions({ vaultOwnerId }) {
const { hasRole, isOwner } = useUserRole();
const canDelete = isOwner(vaultOwnerId) && hasRole('VAULT_OWNER');

return (
<>
{canDelete && (
<Button onClick={handleDelete}>Delete Vault</Button>
)}
</>
);
}

Caching Role Information​

Cache user roles to reduce API calls:

// Fetch once, cache in memory
const { roles } = await fetchUserRoles();
localStorage.setItem('user_roles', JSON.stringify(roles));

// Reuse for permission checks
const hasRole = (required) => roles.includes(required);

Testing with Different Roles​

Creating Test Users​

For testing, create users with specific roles:

-- Grant VAULT_OWNER to test user
INSERT INTO role_grants (user_id, role)
VALUES ('test-user-id', 'VAULT_OWNER');

-- Grant VAULT_ADMIN to another user
INSERT INTO role_grants (user_id, role)
VALUES ('admin-user-id', 'VAULT_ADMIN');

Test Scenarios​

  1. VAULT_VIEWER - Basic access testing
  2. VAULT_OPERATOR - Shadow release testing
  3. VAULT_ADMIN - Real release testing
  4. VAULT_OWNER - Full management testing
  5. Cross-user access - Verify 403 errors

Migration Guide​

Updating Existing Integrations​

If your integration predates role-based access:

  1. Check Error Responses

    • 403 errors now include required and actual roles
    • Use this to guide users to upgrade
  2. Add Role Checks

    • Use _meta fields in responses
    • Show appropriate UI based on permissions
  3. Handle Disabled Actions

    • Show tooltips explaining role requirements
    • Provide role upgrade flows
  4. Update Tests

    • Test with VAULT_VIEWER (minimum role)
    • Verify error responses for insufficient roles
    • Check metadata fields in responses


Last Updated: October 5, 2025