AI Agent Passport Expiry Guide: Ephemeral Credentials & Best Practices

From 15-minute ephemeral credentials to perpetual passports. Real API examples, security best practices, compliance mapping, 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 (per Zero Trust principles)
  • ✅ Reduces risk of credential theft
  • ✅ Enforces time-boxed access control
  • ✅ Automatic credential revocation (no manual cleanup)

Example pattern:

A fintech team can use 15-minute ephemeral credentials for payment processing agents. If credentials are compromised, the useful attack window is limited to the credential lifetime, and the agent cannot continue processing after expiry without renewal.


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: Match agent access to 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
  }
}

This balances security with operational flexibility. You get periodic re-verification without constant credential management overhead, and it maps to compliance requirements like quarterly reviews.

Example pattern:

An e-commerce team can use 90-day credentials for seasonal support agents. Credentials expire after the holiday season, creating a default cleanup path instead of relying only on manual offboarding.


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
  }
}

Annual expiry creates a predictable point for access review, policy review, and audit evidence collection. Stale credentials are less likely to accumulate when renewal is tied to an explicit review workflow.

Example pattern:

A wealth management team can use 365-day credentials for portfolio rebalancing agents, then require mandate review and policy confirmation before renewal.


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: fewer credential-related outages when expiry and rotation are planned around operational requirements.


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, per Zero Trust).

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

This gives you ecosystem interoperability with other VC/DID systems, W3C standards that won't be deprecated, and vendor neutrality (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: Maps directly to 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

Operational trade-off:

A fintech team using 15-minute ephemeral credentials for payment processing agents accepts more renewal complexity in exchange for a shorter useful attack window.

Compliance alignment

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

Example pattern:

A healthcare team can use 365-day credentials for data access agents so renewal requires an explicit security review and access audit.


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: Meet 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
  }'

What you get

APort's passport expiry system covers four credential durations (ephemeral, medium-term, long-term, perpetual) with W3C Verifiable Credential compatibility. Existing passports stay perpetual with no migration required. The expires_in_days convenience field makes the API straightforward to use, and expiry durations can be mapped to your internal security, audit, and regulatory evidence requirements.

Where this helps:

  • Incident response agents can use short-lived passports that expire after a narrow response window.
  • Customer support agents can rotate medium-term passports on a schedule that matches internal access reviews.
  • Financial operations agents can pair longer-lived passports with stronger assurance, tighter limits, and explicit audit review.
  • Long-lived infrastructure agents can remain perpetual only when monitoring, suspend controls, and periodic review are in place.

Next steps:


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