Security Best Practices
Follow these security guidelines to protect your agents, tokens, and sensitive operations.
API Key Security
Storage
- Never commit API keys to source control - Use environment variables or secrets managers
- Use secrets management services - AWS Secrets Manager, HashiCorp Vault, or similar
- Rotate keys regularly - Implement a 90-day rotation policy
- Use separate keys per environment - Different keys for dev, staging, and production
// ❌ Bad: Hardcoded API key
const client = new AgentOTPClient({
apiKey: 'ak_live_xxxx',
});
// ✅ Good: Environment variable
const client = new AgentOTPClient({
apiKey: process.env.AGENT_OTP_API_KEY!,
});
// ✅ Better: Secrets manager
import { SecretsManager } from 'aws-sdk';
const secrets = new SecretsManager();
const { SecretString } = await secrets.getSecretValue({
SecretId: 'agent-otp/api-key',
}).promise();
const client = new AgentOTPClient({
apiKey: JSON.parse(SecretString!).apiKey,
});Key Rotation
// Support multiple keys during rotation
const apiKey = process.env.AGENT_OTP_API_KEY_NEW
|| process.env.AGENT_OTP_API_KEY;
// After deploying with new key, remove old key from environment
// and revoke it via CLI: bun run cli agent:revoke --id AGENT_IDToken Security
Token Handling
- Use tokens immediately - Don't store them for later use
- Never log tokens - They are sensitive credentials
- Set short TTLs - Use the minimum TTL needed
- Verify before critical operations - Call
verifyTokenbefore high-risk actions
// ❌ Bad: Logging tokens
console.log('Token:', permission.token);
// ✅ Good: Log permission ID only
console.log('Permission ID:', permission.id);
// ❌ Bad: Storing tokens
await cache.set('user_token', permission.token);
// ✅ Good: Use immediately
if (permission.status === 'approved') {
await performAction(permission.token);
await otp.useToken(permission.id, permission.token);
}Scope Design
Principle of Least Privilege
Request only the minimum scope needed:
// ❌ Bad: Overly broad scope
const permission = await otp.requestPermission({
action: 'email.send',
scope: {
max_emails: 100,
allowed_recipients: ['*'],
},
});
// ✅ Good: Minimal scope
const permission = await otp.requestPermission({
action: 'email.send',
scope: {
max_emails: 1,
allowed_recipients: [specificRecipient],
subject_pattern: '^Invoice #\\d+$',
},
});Scope Validation
Always validate that the granted scope meets your needs:
const permission = await otp.requestPermission({
action: 'file.write',
scope: { max_size: 10485760 }, // Request 10MB
});
// Check granted scope
if (permission.scope.max_size < requiredSize) {
throw new Error('Insufficient scope granted');
}Context for Audit Trail
Always provide meaningful context for audit purposes:
const permission = await otp.requestPermission({
action: 'payment.transfer',
scope: { max_amount: 100 },
context: {
// Who triggered this?
triggered_by: 'user_request',
user_id: userId,
// What is it for?
reason: 'Monthly subscription payment',
invoice_id: invoiceId,
// When did this happen?
timestamp: new Date().toISOString(),
// Where did it come from?
source_ip: requestIp,
user_agent: userAgent,
},
});Error Handling
Secure Error Messages
try {
const permission = await otp.requestPermission({...});
} catch (error) {
// ❌ Bad: Exposing internal details
console.error('Full error:', error);
return res.status(500).json({ error: error.message });
// ✅ Good: Log internally, return generic message
logger.error('OTP request failed', {
code: error.code,
permissionId: error.permissionId,
// Don't log tokens or sensitive data
});
return res.status(500).json({
error: 'Operation failed. Please try again.',
});
}Network Security
TLS/SSL
- Always use HTTPS - The SDK enforces HTTPS by default
- Verify certificates - Don't disable certificate validation
- Use TLS 1.2 or higher - Older protocols are disabled
Firewall Rules
# Allow outbound to Agent OTP API
iptables -A OUTPUT -p tcp -d api.agentotp.com --dport 443 -j ACCEPT
# For self-hosted: restrict API access to known IPs
iptables -A INPUT -p tcp --dport 3000 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 3000 -j DROPMonitoring and Alerting
Key Metrics to Monitor
- Denial rate - Sudden increase may indicate attack
- Request volume - Unusual spikes need investigation
- Token usage patterns - Unused tokens may indicate issues
- Failed authentications - May indicate compromised keys
// Set up alerts
const metrics = await otp.getMetrics({ period: '1h' });
if (metrics.denialRate > 0.5) {
alert('High denial rate detected', {
rate: metrics.denialRate,
threshold: 0.5,
});
}
if (metrics.unusedTokenRate > 0.3) {
alert('High unused token rate', {
rate: metrics.unusedTokenRate,
});
}Compliance
Audit Log Retention
Configure retention based on your compliance requirements:
- SOC 2 - 1 year minimum
- HIPAA - 6 years
- GDPR - As long as necessary, with deletion capability
Data Residency
For data residency requirements, use self-hosting or specify region:
// Use region-specific endpoint
const client = new AgentOTPClient({
apiKey: process.env.AGENT_OTP_API_KEY!,
baseUrl: 'https://api.eu.agentotp.com', // EU region
});Security Checklist
Pre-Production Checklist
- ☐ API keys stored in secrets manager
- ☐ Environment-specific keys configured
- ☐ Key rotation policy documented
- ☐ Policies reviewed and tested
- ☐ Explicit denies for dangerous operations
- ☐ Scope templates minimize permissions
- ☐ Error handling doesn't leak sensitive info
- ☐ Audit logging configured
- ☐ Monitoring and alerting set up
- ☐ TLS/SSL verified
- ☐ Firewall rules configured
- ☐ Compliance requirements documented
Reporting Security Issues
If you discover a security vulnerability in Agent OTP:
- Email: security@agentotp.com
- PGP Key: Available at security.txt
- Please do not disclose publicly until we've had time to address the issue