Agent Identity
Cryptographic authentication and identity management for AI agents.
Agent Identity
Agent identity provides cryptographic authentication for your AI agents. Each agent gets a unique identity with an Ed25519 key pair, enabling:
- Authentication - Verify which agent made a request
- Authorization - Control what each agent can do
- Audit trails - Track all actions to specific agents
- Trust levels - Differentiate development vs production agents
Overview
When you register an agent with Bastio, you receive:
- Agent ID - Unique identifier (
bastio_agent_xxx) - Public Key - Ed25519 public key for verification
- Private Key - Ed25519 private key for signing (keep secret!)
Agents sign their requests, and Bastio verifies the signature before processing.
Registering an Agent
Via Dashboard
Navigate to Agent Security > Agents and click "Register Agent".
Via API
curl -X POST https://api.bastio.com/v1/guard/{proxyId}/agents \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Customer Support Agent",
"description": "Handles customer inquiries and support tickets",
"trust_level": "standard"
}'Response:
{
"agent_id": "bastio_agent_abc123xyz",
"name": "Customer Support Agent",
"public_key": "MCowBQYDK2VwAyEA...",
"private_key": "MC4CAQAwBQYDK2VwBCIEIP...",
"trust_level": "standard",
"created_at": "2024-01-15T10:00:00Z"
}Store the private key securely! It won't be shown again. Use a secrets manager like AWS Secrets Manager, HashiCorp Vault, or environment variables.
Trust Levels
| Level | Description | Use Case |
|---|---|---|
development | Relaxed policies, higher logging | Testing and development |
standard | Normal policy evaluation | Production agents |
elevated | Trusted for sensitive operations | Internal tools, admin tasks |
restricted | Stricter policies, extra scrutiny | Untrusted or new agents |
Trust levels affect policy evaluation:
// Policy with trust level condition
{
"name": "Allow Elevated Agents Only",
"tool_pattern": "admin_*",
"action": "allow",
"conditions": {
"agent_trust_level": ["elevated"]
}
}Authenticating Requests
Signing Requests
Sign your tool validation requests with the agent's private key:
import base64
import json
import time
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
def sign_request(private_key_pem: str, request_body: dict) -> dict:
"""Sign a request with Ed25519 private key."""
# Load private key
private_key = serialization.load_pem_private_key(
private_key_pem.encode(),
password=None
)
# Create signing payload
timestamp = int(time.time())
payload = {
"body": json.dumps(request_body, sort_keys=True),
"timestamp": timestamp
}
payload_bytes = json.dumps(payload, sort_keys=True).encode()
# Sign
signature = private_key.sign(payload_bytes)
signature_b64 = base64.b64encode(signature).decode()
# Return headers to include
return {
"X-Bastio-Agent-Id": agent_id,
"X-Bastio-Signature": signature_b64,
"X-Bastio-Timestamp": str(timestamp)
}
# Usage
headers = sign_request(AGENT_PRIVATE_KEY, tool_call_body)
response = requests.post(
f"https://api.bastio.com/v1/guard/{proxy_id}/tool",
headers={
"Authorization": f"Bearer {API_KEY}",
**headers
},
json=tool_call_body
)import * as crypto from 'crypto';
interface SignedHeaders {
'X-Bastio-Agent-Id': string;
'X-Bastio-Signature': string;
'X-Bastio-Timestamp': string;
}
function signRequest(
privateKeyPem: string,
agentId: string,
requestBody: object
): SignedHeaders {
// Create signing payload
const timestamp = Math.floor(Date.now() / 1000);
const payload = JSON.stringify({
body: JSON.stringify(requestBody),
timestamp,
});
// Sign with Ed25519
const privateKey = crypto.createPrivateKey(privateKeyPem);
const signature = crypto.sign(null, Buffer.from(payload), privateKey);
return {
'X-Bastio-Agent-Id': agentId,
'X-Bastio-Signature': signature.toString('base64'),
'X-Bastio-Timestamp': timestamp.toString(),
};
}
// Usage
const signedHeaders = signRequest(AGENT_PRIVATE_KEY, AGENT_ID, toolCallBody);
const response = await fetch(`https://api.bastio.com/v1/guard/${proxyId}/tool`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
...signedHeaders,
},
body: JSON.stringify(toolCallBody),
});Request Headers
| Header | Description |
|---|---|
X-Bastio-Agent-Id | Agent ID (bastio_agent_xxx) |
X-Bastio-Signature | Base64-encoded Ed25519 signature |
X-Bastio-Timestamp | Unix timestamp (prevents replay attacks) |
Signature Verification
Bastio verifies:
- Agent exists - Agent ID is registered and not revoked
- Signature valid - Signature matches request content
- Timestamp fresh - Request is within 5 minutes
Managing Agents
List Agents
curl https://api.bastio.com/v1/guard/{proxyId}/agents \
-H "Authorization: Bearer YOUR_API_KEY"Get Agent Details
curl https://api.bastio.com/v1/guard/{proxyId}/agents/{agentId} \
-H "Authorization: Bearer YOUR_API_KEY"Update Agent
curl -X PUT https://api.bastio.com/v1/guard/{proxyId}/agents/{agentId} \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Agent Name",
"trust_level": "elevated"
}'Revoke Agent
curl -X DELETE https://api.bastio.com/v1/guard/{proxyId}/agents/{agentId} \
-H "Authorization: Bearer YOUR_API_KEY"Revoked agents immediately lose access. All subsequent requests will be rejected.
Key Rotation
Rotate agent keys periodically for security:
curl -X POST https://api.bastio.com/v1/guard/{proxyId}/agents/{agentId}/rotate-key \
-H "Authorization: Bearer YOUR_API_KEY"Response includes the new key pair:
{
"agent_id": "bastio_agent_abc123xyz",
"public_key": "MCowBQYDK2VwAyEA...",
"private_key": "MC4CAQAwBQYDK2VwBCIEIP...",
"previous_key_valid_until": "2024-01-22T10:00:00Z"
}The previous key remains valid for 7 days to allow graceful migration.
Per-Agent Tool Restrictions
Restrict which tools each agent can use:
Allowed Tools
Only permit specific tools:
curl -X PUT https://api.bastio.com/v1/guard/{proxyId}/agents/{agentId} \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"allowed_tools": ["read_file", "write_file", "search_files"]
}'Blocked Tools
Block specific tools:
curl -X PUT https://api.bastio.com/v1/guard/{proxyId}/agents/{agentId} \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"blocked_tools": ["execute_shell", "http_post", "db_admin"]
}'Tool restrictions are evaluated before policies:
Agent Tool Call
│
▼
┌─────────────────┐
│ Agent Allowed/ │
│ Blocked Tools │ → Block if restricted
└─────────────────┘
│
▼
┌─────────────────┐
│ Policy Engine │ → Normal policy evaluation
└─────────────────┘Session Management
Track agent sessions:
Active Sessions
curl https://api.bastio.com/v1/guard/{proxyId}/agents/{agentId}/sessions \
-H "Authorization: Bearer YOUR_API_KEY"{
"sessions": [
{
"session_id": "session_abc123",
"started_at": "2024-01-15T10:00:00Z",
"last_activity": "2024-01-15T10:30:00Z",
"tool_calls": 45,
"risk_score_avg": 0.12
}
]
}Terminate Session
curl -X POST https://api.bastio.com/v1/guard/{proxyId}/agents/{agentId}/sessions/{sessionId}/terminate \
-H "Authorization: Bearer YOUR_API_KEY"Agent Activity Logs
View agent activity:
curl https://api.bastio.com/v1/guard/{proxyId}/agents/{agentId}/activity \
-H "Authorization: Bearer YOUR_API_KEY" \
-G \
-d "start_time=2024-01-01T00:00:00Z" \
-d "limit=100"{
"activity": [
{
"timestamp": "2024-01-15T10:30:00Z",
"tool_name": "read_file",
"action": "allow",
"risk_score": 0.1,
"session_id": "session_abc"
}
]
}Code Examples
Complete Agent Integration
import os
import httpx
from dataclasses import dataclass
@dataclass
class BastioAgent:
agent_id: str
private_key: str
proxy_id: str
api_key: str
async def validate_tool(self, session_id: str, tool_call: dict) -> dict:
"""Validate a tool call with agent authentication."""
body = {
"session_id": session_id,
"tool_call": tool_call
}
# Sign request
headers = sign_request(self.private_key, body)
headers["Authorization"] = f"Bearer {self.api_key}"
headers["Content-Type"] = "application/json"
async with httpx.AsyncClient() as client:
response = await client.post(
f"https://api.bastio.com/v1/guard/{self.proxy_id}/tool",
headers=headers,
json=body
)
return response.json()
# Initialize agent
agent = BastioAgent(
agent_id=os.environ["BASTIO_AGENT_ID"],
private_key=os.environ["BASTIO_AGENT_PRIVATE_KEY"],
proxy_id=os.environ["BASTIO_PROXY_ID"],
api_key=os.environ["BASTIO_API_KEY"]
)
# Use in your agent loop
async def execute_tool_with_validation(session_id: str, tool_call: dict):
result = await agent.validate_tool(session_id, tool_call)
if result["action"] == "allow":
return await execute_tool(tool_call)
else:
return f"Tool blocked: {result['message']}"class BastioAgent {
constructor(
private agentId: string,
private privateKey: string,
private proxyId: string,
private apiKey: string
) {}
async validateTool(sessionId: string, toolCall: object): Promise<any> {
const body = {
session_id: sessionId,
tool_call: toolCall,
};
const signedHeaders = signRequest(this.privateKey, this.agentId, body);
const response = await fetch(
`https://api.bastio.com/v1/guard/${this.proxyId}/tool`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
...signedHeaders,
},
body: JSON.stringify(body),
}
);
return response.json();
}
}
// Initialize
const agent = new BastioAgent(
process.env.BASTIO_AGENT_ID!,
process.env.BASTIO_AGENT_PRIVATE_KEY!,
process.env.BASTIO_PROXY_ID!,
process.env.BASTIO_API_KEY!
);
// Use in your agent
async function executeWithValidation(sessionId: string, toolCall: object) {
const result = await agent.validateTool(sessionId, toolCall);
if (result.action === 'allow') {
return await executeTool(toolCall);
} else {
return `Tool blocked: ${result.message}`;
}
}Best Practices
Next Steps
- Policies - Configure trust-level based policies
- Human-in-the-Loop - Route high-risk agent requests
- Chain Analysis - Detect multi-tool attacks