Skip to main content

Agent Authentication

ZewstID provides first-class support for AI agent identities. Agents are registered with unique credentials, assigned trust levels, and tracked through audit logs.

Overview

Unlike regular service accounts, agents have additional properties:

  • Trust levels that control what they can access
  • Capabilities that declare what they can do
  • Audit trails for every action they take
  • Delegation support for acting on behalf of users
┌──────────────────────────────────────────────────┐ │ Agent Lifecycle │ │ │ │ Register ──► Sandboxed ──► Registered ──► Verified │ │ │ Trust Level: untrusted basic elevated │ │ Capabilities: limited standard full │ │ Audit: all logged all logged all logged│ └──────────────────────────────────────────────────┘

Registering an Agent

Via the Developer Portal

  1. Navigate to Agents in the left sidebar
  2. Click Register Agent
  3. Fill in the agent details:
    • Name — A descriptive name (e.g., "Customer Support Bot")
    • Type
      autonomous
      ,
      user-delegated
      , or
      service
    • Description — What the agent does
    • Capabilities — What the agent can do (e.g.,
      read_users
      ,
      send_notifications
      )
  4. Click Register — you'll receive credentials

Via the API

curl -X POST https://api.zewstid.com/api/v1/agents \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Customer Support Bot", "type": "autonomous", "description": "Handles tier-1 support tickets", "capabilities": ["read_users", "read_tickets", "send_notifications"] }'

Response:

{ "id": "agent_xyz789", "clientId": "agent-customer-support-bot", "clientSecret": "zs_agent_secret_xxxxx", "name": "Customer Support Bot", "type": "autonomous", "trustLevel": "sandboxed", "capabilities": ["read_users", "read_tickets", "send_notifications"], "status": "active", "createdAt": "2026-02-20T10:00:00Z" }

Agent Types

TypeDescriptionUse Case
autonomous
Acts independently without user interactionBackground processing, monitoring
user-delegated
Acts on behalf of a user with delegated permissionsAI assistants, user-facing bots
service
Internal service-to-service communicationMicroservice backends

Trust Levels

Agents start at

sandboxed
and can be promoted as they demonstrate reliability:

LevelAccessPromotion Rule
sandboxed
Read-only, rate-limited, no delegationDefault for new agents
registered
Standard API access, basic delegationManual promotion by admin
verified
Full API access, delegation, A2A exchangeAfter review and audit
privileged
Admin-level access, cross-tenant operationsRequires explicit approval

Updating Trust Level

Via the portal: Use the trust level dropdown on each agent card.

Via the API:

curl -X POST https://api.zewstid.com/api/v1/agents/agent_xyz789/trust \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "trustLevel": "registered", "reason": "Completed sandbox testing successfully" }'

Capabilities

Capabilities declare what an agent can do. They are checked at runtime when the agent makes API calls.

Built-in Capabilities

CapabilityDescription
read_users
Read user profiles
write_users
Create and update users
read_tickets
Access support tickets
send_notifications
Send emails/push notifications
manage_sessions
List and revoke sessions
read_analytics
Access analytics data
delegate
Request delegation from users
a2a_exchange
Exchange tokens with other agents

Managing Capabilities

# Get current capabilities curl https://api.zewstid.com/api/v1/agents/agent_xyz789/capabilities \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" # Update capabilities curl -X PUT https://api.zewstid.com/api/v1/agents/agent_xyz789/capabilities \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "capabilities": ["read_users", "send_notifications", "delegate"] }'

Getting Agent Tokens

Agents authenticate the same way as service accounts — using

client_credentials
:

curl -X POST https://api.zewstid.com/api/v1/oauth/token \ -H "Content-Type: application/json" \ -d '{ "grant_type": "client_credentials", "client_id": "agent-customer-support-bot", "client_secret": "zs_agent_secret_xxxxx" }'

The returned token includes agent metadata:

{ "access_token": "eyJhbGciOiJSUzI1NiIs...", "token_type": "Bearer", "expires_in": 3600, "agent_id": "agent_xyz789", "trust_level": "registered" }

Audit Log

Every agent action is recorded in the audit log. View it via the API:

curl https://api.zewstid.com/api/v1/agents/agent_xyz789/audit \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response:

{ "entries": [ { "timestamp": "2026-02-20T10:05:00Z", "action": "token_issued", "ip": "10.0.0.5", "details": { "scopes": ["users:read"] } }, { "timestamp": "2026-02-20T10:05:01Z", "action": "api_call", "endpoint": "GET /api/v1/m2m/users", "status": 200 } ] }

Node SDK Usage

The

@zewstid/node
SDK provides a
ZewstIDAgent
class:

import { ZewstIDAgent } from '@zewstid/node'; const agent = new ZewstIDAgent({ domain: 'auth.zewstid.com', clientId: process.env.AGENT_CLIENT_ID!, clientSecret: process.env.AGENT_CLIENT_SECRET!, agentId: 'agent_xyz789', }); // Get a token (cached and refreshed automatically) const token = await agent.getToken(); // Request delegation from a user const delegation = await agent.requestDelegation({ userId: 'user_123', scopes: ['profile:read', 'orders:read'], reason: 'Access your order history for support', expiresIn: 3600, }); // List delegations const delegations = await agent.listDelegations();

Security Considerations

  1. Credential storage — Store agent secrets in environment variables or a secrets manager
  2. Least privilege — Only request capabilities the agent actually needs
  3. Trust escalation — Start agents at
    sandboxed
    and promote gradually
  4. Audit review — Regularly review agent audit logs for anomalies
  5. Credential rotation — Rotate agent credentials every 90 days
  6. Revocation — Disable agents immediately if compromised

Kill Switch

The kill switch provides instant, defense-in-depth agent termination. When activated, the agent is simultaneously blacklisted in the real-time cache (for immediate token rejection) and disabled at the identity provider level (for persistent disablement).

Activating the Kill Switch

curl -X POST https://api.zewstid.com/api/v1/agents/agent_xyz789/kill \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "reason": "Agent exhibiting unauthorized data access patterns" }'

Response:

{ "success": true, "agentId": "agent_xyz789", "status": "killed", "killedAt": "2026-02-20T15:30:00Z", "reason": "Agent exhibiting unauthorized data access patterns" }

Once killed, all existing tokens are immediately rejected and new token requests fail. The agent receives an

AgentKilledError
on its next API call.

Recovering an Agent

curl -X POST https://api.zewstid.com/api/v1/agents/agent_xyz789/recover \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN"

Recovery re-enables the agent at the identity provider level and removes the real-time blacklist entry. A new client secret is issued — the old secret is permanently invalidated.

Viewing Kill Events

curl https://api.zewstid.com/api/v1/agents/agent_xyz789/kill-events \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN"

Returns the full kill/recover history for audit purposes.

SDK Usage

import { ZewstIDAgent, AgentKilledError } from '@zewstid/node'; const agent = new ZewstIDAgent({ /* config */ }); try { const token = await agent.getToken(); } catch (err) { if (err instanceof AgentKilledError) { console.error('Agent has been killed:', err.message); process.exit(1); } }

Human-in-the-Loop (HITL)

HITL policies require human approval before agents can execute sensitive actions. Policies match requests using glob patterns on action and resource fields, with configurable approval modes and timeouts.

Creating a Policy

curl -X POST https://api.zewstid.com/api/v1/agents/hitl/policies \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Require approval for user deletion", "actionPattern": "delete_*", "resourcePattern": "users/*", "approvalMode": "async", "timeoutSeconds": 300, "approverType": "user", "approverId": "user_admin_123", "autoDenyOnTimeout": true, "priority": 10 }'

Policy fields:

FieldDescription
actionPattern
Glob pattern matched against the action (e.g.,
delete_*
,
transfer_funds
)
resourcePattern
Glob pattern matched against the resource (e.g.,
users/*
,
accounts/prod/*
)
approvalMode
sync
(agent waits) or
async
(agent polls)
timeoutSeconds
How long before the request expires (1-3600)
approverType
user
or
role
approverId
User ID or role name of the approver
autoDenyOnTimeout
If
true
, request is denied when timeout expires
priority
Higher priority policies are evaluated first

Managing Policies

# List all policies curl https://api.zewstid.com/api/v1/agents/hitl/policies \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN" # Update a policy curl -X PATCH https://api.zewstid.com/api/v1/agents/hitl/policies/policy_123 \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "timeoutSeconds": 600, "autoDenyOnTimeout": false }' # Delete a policy curl -X DELETE https://api.zewstid.com/api/v1/agents/hitl/policies/policy_123 \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN"

Requesting Approval (Agent Side)

curl -X POST https://api.zewstid.com/api/v1/agents/hitl/request \ -H "Authorization: Bearer AGENT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "action": "delete_user", "resource": "users/user_456", "context": { "reason": "Account cleanup", "requestedBy": "support_agent" } }'

Response:

{ "requestId": "hitl_req_abc123", "status": "pending_approval", "expiresAt": "2026-02-20T15:35:00Z" }

Polling for Approval

curl https://api.zewstid.com/api/v1/agents/hitl/request/hitl_req_abc123 \ -H "Authorization: Bearer AGENT_TOKEN"

Returns

pending_approval
,
approved
,
denied
, or
expired
.

Approving / Denying (Human Side)

# Approve curl -X POST https://api.zewstid.com/api/v1/agents/hitl/request/hitl_req_abc123/approve \ -H "Authorization: Bearer APPROVER_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "reason": "Verified account cleanup is appropriate" }' # Deny curl -X POST https://api.zewstid.com/api/v1/agents/hitl/request/hitl_req_abc123/deny \ -H "Authorization: Bearer APPROVER_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "reason": "User still has active subscriptions" }'

SDK Usage

const approval = await agent.requestApproval({ action: 'delete_user', resource: 'users/user_456', context: { reason: 'Account cleanup' }, }); // Poll until resolved let status = await agent.getApprovalStatus(approval.requestId); while (status.status === 'pending_approval') { await new Promise(r => setTimeout(r, 2000)); status = await agent.getApprovalStatus(approval.requestId); } if (status.status === 'approved') { // Proceed with action }

JIT (Just-In-Time) Privileges

JIT allows agents to request short-lived elevated privileges for specific actions. Grants can be auto-approved based on policy or require HITL approval.

Requesting a JIT Grant

curl -X POST https://api.zewstid.com/api/v1/jit/request \ -H "Authorization: Bearer AGENT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "action": "read_pii", "resource": "users/user_789/profile", "scopes": ["users:read:pii"], "duration": 300, "context": { "ticketId": "SUPPORT-1234" } }'

Response:

{ "grantId": "jit_grant_xyz", "status": "active", "expiresAt": "2026-02-20T15:35:00Z", "scopes": ["users:read:pii"] }

If HITL approval is required,

status
will be
pending_approval
instead.

Grant Lifecycle

Request ──► pending_approval ──► active ──► expired │ │ ▼ ▼ denied revoked

Checking Grant Status

curl https://api.zewstid.com/api/v1/jit/grants/jit_grant_xyz/status \ -H "Authorization: Bearer AGENT_TOKEN"

Revoking a Grant (Admin)

curl -X POST https://api.zewstid.com/api/v1/jit/grants/jit_grant_xyz/revoke \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "reason": "Security incident" }'

SDK Usage

const grant = await agent.requestJIT({ action: 'read_pii', resource: 'users/user_789/profile', duration: 300, }); if (grant.status === 'active') { // Use elevated privileges within the TTL } const status = await agent.getJITStatus(grant.grantId);

RAR (Rich Authorization Requests)

RAR implements RFC 9396 to provide fine-grained authorization. Instead of broad scopes, agents request specific

authorization_details
that describe exactly what they need to do.

Registering an Authorization Type

curl -X POST https://api.zewstid.com/api/v1/rar/types \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "type": "payment_transfer", "displayName": "Payment Transfer", "description": "Authorization for fund transfers", "allowedActions": ["initiate", "approve", "cancel"], "allowedLocations": ["us", "eu"], "schema": { "type": "object", "properties": { "amount": { "type": "number", "maximum": 10000 }, "currency": { "type": "string", "enum": ["USD", "EUR", "GBP"] }, "recipient": { "type": "string" } }, "required": ["amount", "currency", "recipient"] } }'

Listing and Retrieving Types

# List all types curl https://api.zewstid.com/api/v1/rar/types \ -H "Authorization: Bearer YOUR_TOKEN" # Get a specific type (includes JSON Schema) curl https://api.zewstid.com/api/v1/rar/types/payment_transfer \ -H "Authorization: Bearer YOUR_TOKEN"

Requesting a Token with RAR

Include

authorization_details
when requesting an agent token:

curl -X POST https://api.zewstid.com/api/v1/oauth/token \ -H "Content-Type: application/json" \ -d '{ "grant_type": "client_credentials", "client_id": "agent-payment-bot", "client_secret": "zs_agent_secret_xxxxx", "authorization_details": [ { "type": "payment_transfer", "actions": ["initiate"], "locations": ["us"], "amount": 500, "currency": "USD", "recipient": "merchant_abc" } ] }'

The server validates the request against the registered JSON Schema and the agent's capability ceiling. If valid, the authorization details are bound to the token.

Validating Authorization Details

curl -X POST https://api.zewstid.com/api/v1/rar/validate \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "authorization_details": [ { "type": "payment_transfer", "actions": ["initiate"], "amount": 500, "currency": "USD", "recipient": "merchant_abc" } ] }'

SDK Usage

const token = await agent.getTokenWithRAR([ { type: 'payment_transfer', actions: ['initiate'], locations: ['us'], amount: 500, currency: 'USD', recipient: 'merchant_abc', }, ]);

Workload Identity Federation (WIF)

WIF enables secretless authentication for agents running on cloud platforms (Kubernetes, AWS, GCP, Azure). Instead of storing client secrets, agents exchange their platform-issued identity tokens for ZewstID tokens.

How It Works

┌─────────────────┐ platform token ┌──────────────┐ ZewstID token ┌─────────────┐ │ Cloud Platform │ ──────────────────► │ ZewstID API │ ──────────────► │ Agent uses │ │ (k8s, AWS, GCP) │ │ /oauth/token │ │ ZewstID API │ └─────────────────┘ └──────────────┘ └─────────────┘

Registering a Trusted Issuer

curl -X POST https://api.zewstid.com/api/v1/workload-identity/issuers \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Production K8s Cluster", "issuerUrl": "https://oidc.eks.us-east-1.amazonaws.com/id/ABCDEF1234567890", "jwksUri": "https://oidc.eks.us-east-1.amazonaws.com/id/ABCDEF1234567890/keys", "platform": "kubernetes", "allowedAudiences": ["sts.amazonaws.com"], "allowedSubjects": ["system:serviceaccount:agents:*"], "maxTokenAgeSeconds": 3600 }'

Creating Identity Mappings

Map platform identities to ZewstID agent identities:

curl -X POST https://api.zewstid.com/api/v1/workload-identity/mappings \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "issuerId": "issuer_abc123", "agentClientId": "agent-payment-bot", "subjectPattern": "system:serviceaccount:agents:payment-bot", "subjectMatchType": "exact", "scopes": ["payments:read", "payments:write"] }'

Token Exchange

Agents exchange their platform token for a ZewstID token:

curl -X POST https://api.zewstid.com/api/v1/oauth/token \ -H "Content-Type: application/json" \ -d '{ "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", "subject_token": "eyJhbGciOiJSUzI1NiIs...", "subject_token_type": "urn:ietf:params:oauth:token-type:jwt" }'

Platform Examples

Kubernetes:

apiVersion: v1 kind: ServiceAccount metadata: name: payment-bot namespace: agents annotations: zewstid.com/agent-client-id: "agent-payment-bot"
import { ZewstIDAgent } from '@zewstid/node'; const agent = new ZewstIDAgent({ clientId: 'agent-payment-bot', agentId: 'agent_payment_bot', workloadIdentity: { platform: 'kubernetes', tokenPath: '/var/run/secrets/tokens/zewstid-token', }, }); // No client secret needed — uses service account token const token = await agent.getToken();

AWS (IAM Roles):

const agent = new ZewstIDAgent({ clientId: 'agent-payment-bot', agentId: 'agent_payment_bot', workloadIdentity: { platform: 'aws', roleArn: 'arn:aws:iam::123456789:role/agent-role', }, });

GCP (Service Accounts):

const agent = new ZewstIDAgent({ clientId: 'agent-payment-bot', agentId: 'agent_payment_bot', workloadIdentity: { platform: 'gcp', serviceAccountEmail: '[email protected]', }, });

Intent Metadata

Intent metadata provides structured context for every agent action, enabling end-to-end traceability across multi-agent chains. Agents attach intent headers to their API calls, which are recorded in the audit log.

Standard Headers

HeaderDescriptionExample
X-ZewstID-Task-ID
Unique task identifier
task_abc123
X-ZewstID-Chain-ID
Chain identifier for multi-hop requests
chain_xyz789
X-ZewstID-Intent-Action
What the agent intends to do
process_refund
X-ZewstID-Intent-Reason
Why the action is being taken
Customer requested refund
X-ZewstID-Intent-Initiator
Who/what initiated the action
support_agent
X-ZewstID-Intent-Depth
Hop level in the chain
0
,
1
,
2
X-ZewstID-Parent-Task-ID
Previous task in the chain
task_parent_456

Querying by Task

curl "https://api.zewstid.com/api/v1/audit/intent/tasks/task_abc123?limit=50" \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN"

Querying by Chain

# All entries in a chain curl "https://api.zewstid.com/api/v1/audit/intent/chains/chain_xyz789" \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN" # Ordered trace (hop-by-hop execution path) curl "https://api.zewstid.com/api/v1/audit/intent/chains/chain_xyz789/trace" \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN"

Searching Audit Entries

curl "https://api.zewstid.com/api/v1/audit/intent/search?intentAction=process_refund&from=2026-02-01&to=2026-02-28" \ -H "Authorization: Bearer YOUR_ADMIN_TOKEN"

Query parameters:

agentClientId
,
intentAction
,
intentInitiator
,
from
,
to
,
limit
,
offset
.

SDK Usage

// Set intent for subsequent API calls agent.setIntent({ action: 'process_refund', reason: 'Customer requested refund for order #1234', initiator: 'support_agent', taskId: 'task_abc123', chainId: 'chain_xyz789', }); // All subsequent API calls include intent headers const result = await agent.processRefund(orderId); // Get current intent const intent = agent.getIntent(); // Clear intent when done agent.clearIntent();

Next Steps

Was this page helpful?

Let us know how we can improve our documentation