Tokens

Tokens provide governed authentication and authorization for AI agents. Issue JWTs signed with ML-DSA (FIPS 204) to control agent access and enforce policies.

Issuing Tokens

Issue a token from an agent:

python
import asqav

asqav.init(api_key="sk_...")
agent = asqav.Agent.get("agent_abc123")

# Issue a token (default: 1 hour expiry)
token = agent.issue_token()

# Custom time-to-live (in seconds)
token = agent.issue_token(ttl=3600)  # 1 hour
token = agent.issue_token(ttl=86400)  # 24 hours

# The JWT string lives on token.token
headers = {"Authorization": f"Bearer {token.token}"}

Token Scope

Restrict a token to specific actions:

python
token = agent.issue_token(
    scope=["users:read", "orders:write"],
    ttl=3600,
)

Token Structure

Tokens are standard JWTs with the following structure:

json
{
  "header": {
    "alg": "ML-DSA-65",
    "typ": "JWT"
  },
  "payload": {
    "iss": "https://api.asqav.com",
    "sub": "agent_abc123",
    "aud": "org_xyz789",
    "exp": 1704067200,
    "iat": 1704063600,
    "jti": "tok_unique123",
    "agent_name": "my-agent",
    "algorithm": "ml-dsa-65"
  }
}

Verifying Tokens

Verify a token via the public POST /api/v1/tokens/verify endpoint. No API key is needed, so any third party can confirm a token was issued by a valid agent:

bash
curl -X POST https://api.asqav.com/api/v1/tokens/verify \
  -H "Content-Type: application/json" \
  -d '{"token": "<pqc-jwt>"}'

# Response
{
  "valid": true,
  "agent_id": "agt_abc123",
  "agent_name": "my-agent",
  "expires_at": "2026-06-11T12:00:00Z"
}

An invalid token returns "valid": false with an error field naming the reason, for example a revoked agent or an expired signature.

SD-JWT (Selective Disclosure)

Enterprise tier can use SD-JWT for selective disclosure of claims:

python
# Issue SD-JWT with disclosable claims
sd_token = agent.issue_sd_token(
    ttl=3600,
    claims={
        "role": "admin",           # Always visible
        "email": "agent@co.com",   # Selectively disclosable
        "department": "engineering"
    },
    disclosable=["email", "department"]
)

# Create presentation with only some claims
presentation = sd_token.present(disclose=["role"])
# Only "role" is visible, email/department are hidden
Tip

SD-JWT is useful for privacy-preserving scenarios where you need to prove agent identity without revealing all metadata.

Scope Tokens

Scope tokens restrict an agent's permissions to a specific set of actions. Use them to follow the principle of least privilege - agents only get access to what they need for a given task.

python
# Create a scope token limited to specific actions
token = agent.create_scope_token(actions=["data:read"], ttl=3600)

# Convert to HTTP header for use in requests
headers = token.to_header()

# Multiple actions
token = agent.create_scope_token(
    actions=["data:read", "api:call"],
    ttl=1800
)

Any action outside the token's scope will be rejected by the policy engine. Scope tokens are signed with the same ML-DSA key as standard tokens and appear in audit trails with their granted scope attached.

Replay Protection

Each scope token includes a unique nonce for replay protection. Receivers should track used nonces and reject duplicates.

Using Tokens

Use tokens as bearer authentication:

python
import requests

token = agent.issue_token()

# Use in HTTP requests
response = requests.get(
    "https://api.example.com/data",
    headers={"Authorization": f"Bearer {token.token}"}
)

Emergency Halt

Kill switch that revokes all agents and invalidates all tokens in your organization immediately. Use during security incidents to stop all agent activity until the situation is resolved.

python
# Kill switch: revoke all agents immediately
asqav.emergency_halt(reason="security incident")

This is a destructive, org-wide operation. Every agent is revoked, every token is invalidated, and every pending gate approval is denied. The halt itself is signed into the audit trail with the provided reason. Agents must be individually re-created after the incident is resolved.

Token Revocation

When an agent is revoked, all its tokens are automatically invalidated:

python
# Revoke agent = invalidate all tokens
agent.revoke(reason="compromised")

After revocation, POST /api/v1/tokens/verify returns "valid": false with "error": "Agent is revoked" for every token the agent ever issued.