Overview

OpenAI Assistants are powerful, but they lack granular permission controls. Once you give an Assistant access to a function, it can call that function whenever the LLM decides to. This creates security risks:

  • Assistants may hallucinate tool calls with incorrect parameters
  • No way to enforce constraints (e.g., "only read, never delete")
  • Limited audit logging for Assistant actions
  • Cannot revoke access without deleting the entire Assistant

ACT solves this by adding a permission layer between your Assistant and your backend APIs.

Architecture

OpenAI Assistant
Calls your functions
ACT Middleware
✓ Validates token
✓ Checks policy
✓ Logs action
Your API
Protected resources

⚠️ Authentication Required

All requests to https://api.acttokens.com require:

  • API Key (in X-Api-Key header) - Platform authentication
  • Capability Token (in request body) - Agent authorization

Learn more about dual-token authentication →

Quick Start

Step 1: Get Your API Key

Sign up for an ACT account and obtain your API key from the dashboard. You'll use this to authenticate REST API calls.

API_KEY="your_api_key_here"
ACT_BASE_URL="https://api.acttokens.com"

Step 2: Register Your Assistant in ACT

curl -X POST $ACT_BASE_URL/v1/agents \
  -H "X-Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "OpenAI Customer Support Assistant",
    "description": "Handles customer inquiries",
    "metadata": {
      "openai_assistant_id": "asst_abc123"
    }
  }'

Step 3: Define a Policy

curl -X POST $ACT_BASE_URL/v1/policies \
  -H "X-Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Customer Support Read Policy",
    "actions": ["read", "list"],
    "resources": ["api://crm/customers/*"],
    "effect": "allow",
    "constraints": {
      "maxRows": 100,
      "allowedDomains": ["yourcompany.com"]
    }
  }'

Step 4: Issue an ACT Token

curl -X POST $ACT_BASE_URL/v1/tokens \
  -H "X-Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "agent_123",
    "expiresIn": 3600
  }'

Step 5: Add ACT Validation to Your Functions

Create a helper function that validates requests with ACT before executing actions:

// Helper function to validate with ACT
async function validateWithACT(token, action, resource) {
  const response = await fetch('$ACT_BASE_URL/v1/enforce', {
    method: 'POST',
    headers: {
      'X-Api-Key': '$API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      requestId: crypto.randomUUID(),
      capabilityToken: token,
      action: action,
      resourceId: resource,
      tenantId: 'default-tenant',
      context: {}
    })
  });

  const result = await response.json();
  return result.decision === 'allowed';
}

// Your OpenAI function that validates
async function getCustomerData(customerId, actToken) {
  const allowed = await validateWithACT(
    actToken, 
    'read',
    `api://crm/customers/${customerId}`
  );

  if (!allowed) {
    throw new Error("Action not permitted by ACT policy");
  }

  // Now fetch the data
  const customer = await db.customers.findById(customerId);
  return customer;
}

Step 6: Run Your Assistant with ACT

import OpenAI from 'openai';

const openai = new OpenAI();

// Create a thread and run
const thread = await openai.beta.threads.create();
const run = await openai.beta.threads.runs.create(thread.id, {
  assistant_id: "asst_abc123",
  metadata: {
    act_token: actToken // Pass ACT token in metadata
  }
});

// When the Assistant calls your function, it includes
// the ACT token, and your function validates it
// (as shown in Step 5)

Example Use Cases

✅ Customer Support Assistant

Policy: Read customer data, create support tickets

actions: ["read", "create"]
resources: ["api://crm/customers/*", "api://tickets/*"]
constraints: { maxRows: 50 }

✅ Data Analysis Assistant

Policy: Read-only access to analytics database

actions: ["read", "query"]
resources: ["api://analytics/*"]
constraints: { maxRows: 1000, readOnly: true }

✅ Email Assistant

Policy: Send emails, only to internal domains

actions: ["send_email"]
resources: ["api://email/*"]
constraints: { allowedDomains: ["@yourcompany.com"] }

Best Practices

  • Use short-lived tokens: Issue ACT tokens with 1-hour expiration for Assistants
  • Validate every function call: Never trust the Assistant to make the right decision — always validate with ACT
  • Log everything: ACT automatically logs all validation attempts, giving you full audit trails
  • Start restrictive: Begin with read-only policies and gradually expand permissions as needed
  • Use constraints: Add row limits, domain allowlists, and other constraints to prevent abuse
  • Monitor audit logs: Regularly review ACT audit logs to detect unusual Assistant behavior

Troubleshooting

Assistant calls are being blocked

Solution: Check your policy. The action or resource may not be allowed. Review ACT audit logs to see exactly what was blocked.

Token expired errors

Solution: Issue a new ACT token. Consider implementing automatic token refresh in your application.

Not seeing audit logs

Solution: Ensure you're calling act.validate() before executing actions. Only validated actions appear in audit logs.