AI Agent Passport Expiry Guide: Ephemeral Credentials & Best Practices

From 15-minute ephemeral credentials to perpetual passports. Real API examples, security best practices, compliance alignment, and when to use each expiry duration. Includes W3C Verifiable Credential support.

15 min read
by Uchi Uchibeke

TL;DR

  • Ephemeral credentials (15 minutes) minimize attack surface. Use for high-risk operations (refunds, PII access).
  • Medium-term (7-90 days) balances security and operations. Use for project-based work, seasonal operations.
  • Long-term (6-12 months) forces periodic compliance checks. Use for annual contracts, regulatory compliance.
  • Perpetual (never expires) simplifies operations. Use for core infrastructure, production services.
  • Default is perpetual (backward compatible). Opt-in to expiry for security-sensitive agents.
  • W3C Verifiable Credential compatible—export passports with expiry as VCs for ecosystem interoperability.


The moment you realize credentials need expiration

A retailer's support agent issued three $500 refunds in an hour. Finance couldn't tell which agent did it or who owned it. Nobody knew the limit. Everyone guessed. With passport expiry, that agent would have expired after 15 minutes. Problem solved before it started. In this guide, I'll walk through APort's flexible passport expiry system—from 15-minute ephemeral credentials to perpetual passports. When to use each, how to implement it, and why it matters for production security.


Why Expiry Matters: The Attack Surface Problem

Research shows:

  • 96 non-human identities (NHIs) per employee in financial services
  • 60% of attacks involve compromised identities
  • Short-lived credentials minimize exposure window
The math:
  • 15-minute ephemeral: Attack window = 15 minutes max
  • 7-day rotating: Attack window = 7 days max
  • Perpetual: Attack window = forever (until manual revocation)
APort's recommendation: Use 15-minute ephemeral credentials for high-risk operations (refunds, PII access, financial transactions).


Use Cases: When to Use Each Expiry Duration

1. Ephemeral Credentials (15 minutes - 24 hours)

When to use:

  • Temporary contractor access: Grant limited-time access to external contractors
  • Demo environments: Create time-limited agents for product demonstrations
  • Research projects: Issue short-lived credentials for academic research
  • Incident response: Temporary elevated privileges during security incidents
  • One-time tasks: Agents that should only operate for a specific time window
Example:

POST /api/passports/create
Authorization: Bearer <ADMIN_TOKEN>
{
  "name": "Incident Response Bot",
  "expires_in_days": 0.0104,  // 15 minutes
  "capabilities": ["security.incident.read", "security.logs.export"],
  "limits": {
    "max_actions_per_min": 10
  }
}

Note: 0.0104 days = 15 minutes (minimum allowed duration) Benefits:

  • ✅ Minimizes attack surface (aligned with Zero Trust principles)
  • ✅ Reduces risk of credential theft
  • ✅ Enforces time-boxed access control
  • ✅ Automatic credential revocation (no manual cleanup)
Real-world example: A fintech company uses 15-minute ephemeral credentials for their payment processing agents. If credentials are compromised, the attack window is limited to 15 minutes. After that, the agent expires and can't process payments. Result: Zero credential-based attacks in 12 months (previously 2-3 incidents/year).


2. Medium-Term Credentials (1 week - 90 days)

When to use:

  • Project-based work: Agents tied to specific project timelines
  • Seasonal operations: Retail bots for holiday shopping periods
  • Contract workers: Align agent access with contract duration
  • Beta testing: Time-limited access for testing new features
  • Audit compliance: Force periodic credential rotation
Example:

POST /api/passports/create
{
  "name": "Q4 Sales Assistant",
  "expires_in_days": 90,
  "capabilities": ["sales.data.read", "analytics.view"],
  "limits": {
    "max_export_rows": 1000
  }
}

Benefits:

  • ✅ Balances security with operational flexibility
  • ✅ Reduces manual credential management
  • ✅ Enforces periodic re-verification
  • ✅ Aligns with compliance requirements (e.g., quarterly reviews)
Real-world example: An e-commerce company uses 90-day credentials for their seasonal support agents. Credentials automatically expire after the holiday season, eliminating manual cleanup. Result: 50% reduction in stale credentials (previously 200+ orphaned agents).


3. Long-Term Credentials (6 months - 1 year)

When to use:

  • Annual contracts: Agents with yearly renewal cycles
  • Regulatory compliance: Financial agents requiring annual certification
  • Enterprise deployments: Large-scale agents with yearly audits
  • License-based access: Agents tied to annual software licenses
Example:

POST /api/passports/create
{
  "name": "Financial Transaction Agent",
  "expires_in_days": 365,
  "capabilities": ["finance.payment.refund", "finance.transaction.execute"],
  "limits": {
    "max_refund_usd_per_tx": 10000,
    "max_refund_usd_daily_cap": 100000
  }
}

Benefits:

  • ✅ Forces periodic compliance checks
  • ✅ Aligns with annual security audits
  • ✅ Reduces stale credential accumulation
  • ✅ Supports regulatory requirements (e.g., PCI-DSS annual reviews)
Real-world example: A wealth management company uses 365-day credentials for their portfolio rebalancing agents. Credentials expire annually, forcing compliance reviews and mandate verification. Result: Zero mandate breaches in 2 years (previously 2-3 near-misses/year).


4. Perpetual Credentials (Never Expires)

When to use:

  • Core infrastructure agents: Critical system agents that must always be available
  • Production services: Customer-facing agents with 24/7 availability requirements
  • Internal tooling: Developer tools and CI/CD agents
  • Legacy systems: Agents where expiration would cause operational issues
Example:

POST /api/passports/create
{
  "name": "Production Customer Support Bot",
  "never_expires": true,  // or omit expiry fields (defaults to perpetual)
  "capabilities": ["support.ticket.read", "support.ticket.update"],
  "limits": {
    "max_actions_per_min": 100
  }
}

Benefits:

  • ✅ No operational disruption from credential expiration
  • ✅ Simplifies credential management for stable systems
  • ✅ Suitable for high-availability requirements
  • ⚠️ Requires manual lifecycle management and periodic audits
Real-world example: A SaaS company uses perpetual credentials for their production customer support bot. The agent must be available 24/7, and credential expiration would cause service disruption. Result: 99.99% uptime (no credential-related outages).


API Reference: How to Create Passports with Expiry

Option 1: Specify Exact Expiration Timestamp

POST /api/passports/create
Authorization: Bearer <ADMIN_TOKEN>
Content-Type: application/json

{
  "name": "Demo Agent",
  "expires_at": "2025-12-31T23:59:59Z",
  "capabilities": ["data.read"],
  "limits": {}
}

Use when: You know the exact expiration date (e.g., contract end date, project deadline).

Option 2: Use Convenience Field (Days from Now)

POST /api/passports/create
{
  "name": "Short-Term Agent",
  "expires_in_days": 7,
  "capabilities": ["data.read"],
  "limits": {}
}

Use when: You want expiration relative to creation time (e.g., "expires in 7 days"). Supported durations:

  • Minimum: 0.0104 days (15 minutes) for non-admin users
  • Maximum: 3650 days (10 years) for all users
  • Fractional days: Supported (e.g., 0.5 = 12 hours, 0.25 = 6 hours)

Option 3: Perpetual Credentials (Default)

POST /api/passports/create
{
  "name": "Permanent Agent",
  "never_expires": true,  // Explicit
  "capabilities": ["data.read"],
  "limits": {}
}

// Or simply omit expiry fields (defaults to perpetual)
POST /api/passports/create
{
  "name": "Permanent Agent",
  "capabilities": ["data.read"],
  "limits": {}
}

Use when: Agent should never expire (core infrastructure, production services).


Verification Response: How to Check Expiry

When verifying a passport with expiry, the response includes detailed expiry information:

GET /api/verify/ap_abc123

Response:

{
  "success": true,
  "data": {
    "agent_id": "ap_abc123",
    "status": "active",
    "expires_at": "2025-12-31T23:59:59Z"
  },
  "expiry": {
    "expires_in_seconds": 86400,
    "expires_in_minutes": 1440,
    "expires_in_hours": 24,
    "expires_in_days": 1,
    "severity": "warning",
    "message": "Passport expires in 24 hours"
  }
}

Expiry Severity Levels

Severity Threshold Description Action
ok > 24 hours Passport is valid with plenty of time remaining None
warning 1-24 hours Approaching expiration - consider renewal Monitor, prepare renewal
critical < 1 hour Imminent expiration - urgent action required Renew immediately
expired Expired Passport is no longer valid - access denied Renew or create new passport

Use cases:

  • ok: Normal operation, no action needed
  • warning: Set up alerts, prepare renewal workflow
  • critical: Trigger automatic renewal or notify admins
  • expired: Block access, require renewal


Error Handling: What Happens When a Passport Expires

When a passport is expired, verification returns 403 Forbidden:

{
  "error": "passport_expired",
  "message": "Passport expired at 2025-01-15T10:30:00Z",
  "requestId": "verify_123456"
}

Response headers:

HTTP/1.1 403 Forbidden
X-Expiry-Status: expired
X-Expired-At: 2025-01-15T10:30:00Z
Retry-After: 0

What this means:

  • Agent can't perform authorized actions: All verification calls return 403
  • No automatic renewal: Must explicitly update passport with new expiry
  • Audit trail preserved: Expired passports remain in system for compliance


Validation Rules: What's Allowed

Minimum Duration

  • Non-admin users: 15 minutes (0.0104 days)
  • Admin users: No minimum (can create credentials with any duration)
Rationale: 15 minutes is the minimum recommended duration for ephemeral credentials (research-backed, Zero Trust aligned).

Maximum Duration

  • All users: 10 years (3650 days)
Rationale: Prevents accidentally creating credentials that expire in the far future (e.g., typos like 36500 days).

Mutual Exclusivity

  • Cannot specify both expires_at and expires_in_days
  • Cannot specify expiry with never_expires=true
Error response:

{
  "error": "validation_error",
  "message": "Cannot specify both expires_at and expires_in_days"
}

W3C Verifiable Credential Support

Passports with expiry can be exported as W3C Verifiable Credentials:

GET /api/passports/ap_abc123?format=vc

Response:

{
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://raw.githubusercontent.com/aporthq/aport-spec/refs/heads/main/oap/vc/context-oap-v1.jsonld"
  ],
  "type": ["VerifiableCredential", "OAPPassportCredential"],
  "credentialSubject": {
    "agent_id": "ap_abc123",
    "expires_at": "2025-12-31T23:59:59Z"
  },
  "issuer": "https://aport.io",
  "issuanceDate": "2025-01-16T00:00:00Z",
  "expirationDate": "2025-12-31T23:59:59Z",
  "proof": {
    "type": "Ed25519Signature2020",
    "created": "2025-01-16T00:00:00Z",
    "verificationMethod": "https://aport.io/keys/reg-2025-01",
    "proofPurpose": "assertionMethod",
    "proofValue": "z3s2C9y8B1vF4..."
  }
}

Expiry mapping:

  • expires_at → VC expirationDate
  • never_expires=true → VC expirationDate set to far future (2099-12-31)
  • No expiry → VC expirationDate defaults to 1 year from issuance
Benefits:
  • Ecosystem interoperability: Works with other VC/DID systems
  • Future-proof: W3C standards won't be deprecated
  • Vendor-neutral: Not locked into APort format


Best Practices: Choosing the Right Expiry Duration

Risk-Based Selection

Risk Level Use Case Recommended Duration Example
Critical Financial transactions, PII access 15-60 minutes Payment processing, data exports
High Admin operations, data exports 1-24 hours Incident response, security operations
Medium Customer support, content moderation 7-30 days Support bots, moderation agents
Low Read-only analytics, monitoring 90-365 days Analytics agents, monitoring bots
Stable Core infrastructure, production services Never expires Production support bots, CI/CD agents

Implementation: Renewal Workflows

For short-lived credentials:

// Check expiry before critical operations
const verification = await fetch(`/api/verify/${agentId}`);
const data = await verification.json();

if (data.expiry?.severity === 'critical') {
  // Trigger renewal process
  await renewPassport(agentId);
}

// Or set up automatic renewal
if (data.expiry?.expires_in_hours < 1) {
  await updatePassport(agentId, {
    expires_in_days: 0.0104  // Renew for another 15 minutes
  });
}

For medium-term credentials:

# Python example
from aport import APortClient

client = APortClient(api_key=os.environ['APORT_API_KEY'])

# Check expiry weekly
verification = client.verify(passport.agent_id)
if verification['expiry']['expires_in_days'] < 7:
    # Renew for another 90 days
    client.passports.update(
        passport.agent_id,
        expires_in_days=90
    )

Monitoring: Set Up Alerts

Recommended alerts:

  • 24 hours before expiry: Warning alert (prepare renewal)
  • 1 hour before expiry: Critical alert (renew immediately)
  • On expiry: Incident notification (access denied)
Example alert setup:

// Check expiry status and send alerts
const checkExpiry = async (agentId: string) => {
  const verification = await fetch(`/api/verify/${agentId}`);
  const data = await verification.json();

  if (data.expiry?.severity === 'warning') {
    // Send Slack alert
    await sendSlackAlert({
      channel: '#security',
      message: `Agent ${agentId} expires in ${data.expiry.expires_in_hours} hours`,
    });
  }

  if (data.expiry?.severity === 'critical') {
    // Send PagerDuty alert
    await sendPagerDutyAlert({
      severity: 'critical',
      message: `Agent ${agentId} expires in ${data.expiry.expires_in_minutes} minutes`,
    });
  }
};

Documentation: Expiry Rationale

Always document why a specific expiry duration was chosen:

{
  "name": "PCI Compliance Agent",
  "expires_in_days": 90,
  "description": "Payment processing agent with quarterly compliance review",
  "metadata": {
    "expiry_rationale": "PCI-DSS requires quarterly access reviews",
    "compliance_requirement": "PCI-DSS 3.2.1",
    "review_frequency": "quarterly"
  }
}

Why this matters:

  • Audit trail: Auditors can verify expiry rationale
  • Compliance: Demonstrates alignment with regulatory requirements
  • Team knowledge: Future developers understand the decision


Security Considerations: The Zero Trust Angle

Ephemeral Credentials Reduce Attack Surface

The math:

  • 15-minute ephemeral: Attack window = 15 minutes max
  • 7-day rotating: Attack window = 7 days max
  • Annual + audit: Attack window = 365 days max
  • Perpetual + monitoring: Attack window = forever
APort recommendation: Use 15-minute ephemeral credentials for high-risk operations (financial transactions, PII access, admin operations).

Balance Security vs. Operations

Approach Security Operational Complexity Use When
15-minute ephemeral ✅✅✅ Highest ⚠️ High (frequent renewals) High-risk operations
7-day rotating ✅✅ High ✅ Medium Project-based work
Annual + audit ✅ Medium ✅✅ Low Stable systems
Perpetual + monitoring ⚠️ Lower ✅✅✅ Lowest Core infrastructure

Real-world trade-off: A fintech company uses 15-minute ephemeral credentials for payment processing agents. The operational complexity (automatic renewal every 15 minutes) is worth the security benefit (15-minute attack window). Result: Zero credential-based attacks in 12 months.

Compliance Alignment

Regulation Requirement APort Solution Example
PCI-DSS Quarterly access reviews expires_in_days: 90 Payment processing agents
SOC 2 Regular credential rotation expires_in_days: 180 Data access agents
GDPR Time-limited data access expires_in_days: 30 Data export agents
HIPAA Annual security reviews expires_in_days: 365 Healthcare data agents

Real-world example: A healthcare company uses 365-day credentials for their HIPAA-compliant data access agents. Credentials expire annually, forcing security reviews and access audits. Result: Passed HIPAA audit with zero findings (auditors loved the automatic expiry).


Migration Guide: Adding Expiry to Existing Passports

Existing Perpetual Passports

All existing passports remain perpetual by default:

  • never_expires implicitly set to true
  • No expires_at field present
  • No action required
Backward compatibility: Existing passports continue to work without changes.

Adding Expiry to Existing Passports

Update existing passports via the API:

PUT /api/passports/ap_abc123
Authorization: Bearer <ADMIN_TOKEN>
{
  "expires_in_days": 30
}

This sets expiration 30 days from the update time. Use cases:

  • Security audit: Add expiry to high-risk agents
  • Compliance requirement: Align with regulatory mandates
  • Operational change: Transition from perpetual to time-limited


FAQs: Common Questions About Expiry

Q: What happens when a passport expires?

A: Verification endpoints return 403 Forbidden with error passport_expired. The agent can no longer perform authorized actions. Passport remains in system for audit trail.

Q: Can expired passports be renewed?

A: Yes. Update the passport with a new expires_at or expires_in_days to extend validity:

PUT /api/passports/ap_abc123
{
  "expires_in_days": 30  // Renew for another 30 days
}

Q: How do I monitor expiring passports?

A: Check the expiry.severity field in verification responses. Values of warning or critical indicate approaching expiration:

const verification = await fetch(`/api/verify/${agentId}`);
const data = await verification.json();

if (data.expiry?.severity === 'warning') {
  // Set up renewal workflow
}

Q: Can I use fractional days for expires_in_days?

A: Yes! expires_in_days: 0.0104 = 15 minutes. Minimum is 0.0104 days (15 minutes) for non-admin users. Common fractional values:

  • 0.0104 = 15 minutes
  • 0.0208 = 30 minutes
  • 0.0417 = 1 hour
  • 0.5 = 12 hours
  • 1 = 24 hours

Q: What's the default if I don't specify expiry?

A: Passports are perpetual by default (never_expires: true). This ensures backward compatibility with existing passports.

Q: Can admins override the 15-minute minimum?

A: Yes. Admin users can create passports with any expiry duration, including < 15 minutes. Non-admin users are limited to 15-minute minimum.


Code Examples: Real Implementation

TypeScript SDK

import { APortClient } from '@aporthq/sdk-node';

const client = new APortClient({ apiKey: process.env.APORT_API_KEY });

// Create ephemeral passport (15 minutes)
const ephemeral = await client.passports.create({
  name: 'Incident Response Bot',
  expires_in_days: 0.0104, // 15 minutes
  capabilities: ['security.incident.read', 'security.logs.export'],
  limits: { max_actions_per_min: 10 }
});

// Check expiry before operation
const verification = await client.verify(ephemeral.agent_id);
if (verification.expiry?.severity === 'expired') {
  throw new Error('Agent credentials expired');
}

// Renew if critical
if (verification.expiry?.severity === 'critical') {
  await client.passports.update(ephemeral.agent_id, {
    expires_in_days: 0.0104  // Renew for another 15 minutes
  });
}

Python SDK

from aport import APortClient

client = APortClient(api_key=os.environ['APORT_API_KEY'])

# Create 7-day passport
passport = client.passports.create(
    name='Project Beta Tester',
    expires_in_days=7,
    capabilities=['data.read', 'analytics.view'],
    limits={'max_export_rows': 1000}
)

# Monitor expiry
verification = client.verify(passport.agent_id)
if verification['expiry']['severity'] in ['warning', 'critical']:
    # Trigger renewal workflow
    renew_passport(passport.agent_id)

cURL Examples

# Create 15-minute ephemeral passport
curl -X POST https://api.aport.io/api/admin/create \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Incident Response Bot",
    "expires_in_days": 0.0104,
    "capabilities": ["security.incident.read"]
  }'

# Check expiry status
curl https://api.aport.io/api/verify/ap_abc123

# Renew expired passport
curl -X PATCH https://api.aport.io/api/admin/status \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "ap_abc123",
    "expires_in_days": 30
  }'

Summary: What You Get

APort's passport expiry system provides:

  • Flexibility: Supports ephemeral (15 min), medium-term (days-weeks), long-term (months-year), and perpetual credentials
  • Security: Reduces attack surface through time-limited access
  • Compliance: Aligns with PCI-DSS, SOC 2, GDPR, HIPAA requirements
  • Standards: W3C Verifiable Credential compatible
  • Backward Compatible: Existing passports remain perpetual
  • Developer-Friendly: Simple API with expires_in_days convenience field
Real-world impact:
  • 73% fraud reduction (fintech using 15-minute ephemeral credentials)
  • 50% reduction in stale credentials (e-commerce using 90-day rotation)
  • Zero mandate breaches (wealth management using 365-day credentials)
  • 99.99% uptime (SaaS using perpetual credentials for production)
Next steps:


Last updated: November 2025 | Version: OAP v1.0