Using ACT with Azure OpenAI
Add fine-grained permissions and runtime enforcement to Azure OpenAI Service deployments
Overview
Azure OpenAI Service is powerful for enterprise deployments, but you need additional governance layers to meet compliance requirements and prevent unauthorized actions. ACT adds a security boundary between your applications and Azure OpenAI resources.
- No granular control over which models and endpoints applications can access
- Difficult to enforce data residency and compliance constraints
- Limited audit trails for regulatory compliance (SOC 2, HIPAA, etc.)
- No way to rate-limit or throttle usage per application
- Risk of data exfiltration through model outputs
ACT solves this by providing enterprise governance for your Azure OpenAI deployments.
Architecture
✓ Checks policy
✓ Logs audit
⚠️ Authentication Required
All requests to https://api.acttokens.com require:
- API Key (in
X-Api-Keyheader) - Platform authentication - Capability Token (in request body) - Agent authorization
Quick Start
Step 1: Get Your API Key
Sign up for ACT and obtain your API key from the dashboard.
ACT_API_KEY="your_api_key_here"
ACT_BASE_URL="https://api.acttokens.com"
AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/"
AZURE_OPENAI_API_KEY="your_azure_openai_key"Step 2: Register Your Application in ACT
curl -X POST $ACT_BASE_URL/v1/agents \
-H "X-Api-Key: $ACT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Customer Portal App",
"description": "Web application using Azure OpenAI for customer support",
"metadata": {
"framework": "azure-openai",
"environment": "production",
"azure_resource": "your-resource"
}
}'Step 3: Define Enterprise Policy
Create policies that enforce your security and compliance requirements:
curl -X POST $ACT_BASE_URL/v1/policies \
-H "X-Api-Key: $ACT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Customer Portal Policy",
"actions": ["chat", "completion"],
"resources": ["api://azure-openai/models/gpt-4"],
"effect": "allow",
"constraints": {
"maxTokensPerRequest": 2000,
"maxRequestsPerDay": 10000,
"allowedTenants": ["your-tenant-id"],
"dataClassification": "internal"
}
}'Step 4: Issue an ACT Token
curl -X POST $ACT_BASE_URL/v1/tokens \
-H "X-Api-Key: $ACT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agentId": "agent_123",
"expiresIn": 3600
}'
# Response: {"token": "eyJhbGc..."}Step 5: Add ACT Validation to Azure OpenAI Calls
Validate requests before calling Azure OpenAI:
using Azure;
using Azure.AI.OpenAI;
using System.Net.Http.Json;
using System.Text.Json;
var actApiKey = Environment.GetEnvironmentVariable("ACT_API_KEY");
var actBaseUrl = Environment.GetEnvironmentVariable("ACT_BASE_URL");
var actToken = "token_from_step_4";
var azureOpenAiKey = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY");
var azureOpenAiEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");
// Helper function to validate with ACT
async Task ValidateWithActAsync(string action, string resource)
{
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Api-Key", actApiKey);
var request = new
{
requestId = Guid.NewGuid().ToString(),
capabilityToken = actToken,
action = action,
resourceId = resource,
tenantId = "default-tenant",
context = new { }
};
var response = await client.PostAsJsonAsync(
$"{actBaseUrl}/v1/enforce", request);
var result = await response.Content.ReadAsAsync<object>;
return result["decision"] == "allowed";
}
// Get Azure OpenAI client
var azureOpenAiClient = new OpenAIClient(
new Uri(azureOpenAiEndpoint),
new AzureKeyCredential(azureOpenAiKey));
// Create chat completion with ACT validation
async Task CreateChatCompletionAsync(string userMessage)
{
// Validate with ACT first
var allowed = await ValidateWithActAsync(
"chat",
"api://azure-openai/models/gpt-4");
if (!allowed)
{
throw new UnauthorizedAccessException(
"Chat request denied by ACT policy");
}
// Safe to call Azure OpenAI
var chatCompletionOptions = new ChatCompletionsOptions()
{
DeploymentName = "gpt-4",
Messages =
{
new ChatMessage(ChatRole.User, userMessage)
}
};
var response = await azureOpenAiClient.GetChatCompletionsAsync(
chatCompletionOptions);
return response.Value.Choices[0].Message.Content;
}Step 6: Call Your Protected API
try
{
var response = await CreateChatCompletionAsync(
"What are the best practices for customer service?");
Console.WriteLine(response);
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine($"Request denied: {ex.Message}");
}Example Use Cases
✅ Multi-Tenant SaaS
Policy: Each tenant can access only specific models with token limits
actions: ["chat", "completion"]
resources: ["api://azure-openai/models/*"]
constraints: {
allowedTenants: ["tenant_id"],
maxTokensPerDay: 50000
}✅ Healthcare Application
Policy: HIPAA-compliant with PHI restrictions
actions: ["completion"]
resources: ["api://azure-openai/models/gpt-4"]
constraints: {
noPersonalData: true,
encryptionRequired: true,
auditLogging: "detailed"
}✅ Internal Tools
Policy: Unrestricted access to all models for employees
actions: ["*"]
resources: ["api://azure-openai/*"]
constraints: {
allowedRoles: ["employee"],
requiresApproval: false
}Best Practices
- Use short-lived tokens: Issue tokens with 1-hour expiration and implement refresh logic
- Enforce token limits: Set maxTokensPerRequest and maxTokensPerDay constraints
- Enable detailed audit logging: Log all Azure OpenAI calls for compliance
- Isolate by tenant: If using Azure OpenAI in multi-tenant scenarios, separate policies per tenant
- Monitor cost: Use request-level tracking to attribute costs to specific applications
- Test policies: Validate policies in staging before production rollout
Troubleshooting
Requests are being blocked
Solution: Check that your policy allows the specific action and resource. Review ACT audit logs for details on why requests were denied.
Token expiration errors
Solution: Implement token refresh logic. Issue new tokens before the previous ones expire, especially for long-running applications.
Azure OpenAI rate limit exceeded
Solution: Use ACT's rate limiting constraints to distribute requests. Set appropriate maxRequestsPerDay limits.