Revocation Package
The revocation packages define the RevocationStore interface and provide an in-memory implementation for development. Production deployments use the Redis-backed implementation from the connectors layer. Any component that verifies mandates must supply a revocation store, because a cryptographically valid mandate from a revoked session must still be rejected.
TypeScript — @caracalai/revocation
Section titled “TypeScript — @caracalai/revocation”npm install @caracalai/revocationRevocationStore interface
Section titled “RevocationStore interface”interface RevocationStore { isRevoked(sid: string): Promise<boolean>; markRevoked(sid: string, ttlMs?: number): Promise<void>;}sid is the session ID from the mandate’s sid claim. Every component that calls authenticate() or the Express/MCP middleware passes a RevocationStore instance. The store is checked on every inbound request against the sid of the presented mandate.
InMemoryRevocationStore
Section titled “InMemoryRevocationStore”import { InMemoryRevocationStore } from '@caracalai/revocation';
const store = new InMemoryRevocationStore();No constructor options. TTL entries are kept in memory. Suitable for single-process development and testing. Not appropriate for production multi-replica deployments — sessions revoked in one replica are not propagated to others.
Behavior
Section titled “Behavior”isRevoked(sid): Returnstrueifsidwas marked revoked and the entry has not expired.markRevoked(sid, ttlMs?): Records the session as revoked.ttlMsdefaults to 24 hours (86,400,000 ms) matching the Gateway’s revocation retention window.- Entries are lazily expired: they are removed on access when the TTL has elapsed.
Python — caracalai-revocation
Section titled “Python — caracalai-revocation”pip install caracalai-revocationRevocationStore protocol
Section titled “RevocationStore protocol”from typing import Protocol
class RevocationStore(Protocol): def is_revoked(self, sid: str) -> bool: ... def mark_revoked(self, sid: str, ttl_ms: int | None = None) -> None: ...All Caracal Python packages that accept a revocation store accept any object implementing this protocol.
InMemoryRevocationStore
Section titled “InMemoryRevocationStore”from caracalai_revocation import InMemoryRevocationStore
DEFAULT_TTL_MS = 24 * 60 * 60 * 1000 # 24 hours
store = InMemoryRevocationStore(default_ttl_ms=DEFAULT_TTL_MS)Constructor options:
| Parameter | Type | Default | Description |
|---|---|---|---|
default_ttl_ms | int | 86400000 | Default TTL applied to mark_revoked when no ttl_ms is supplied |
Behavior
Section titled “Behavior”is_revoked(sid): ReturnsTrueif the SID is marked revoked and its entry has not expired.mark_revoked(sid, ttl_ms?): Records the SID as revoked; usesdefault_ttl_msifttl_msisNone.- Not thread-safe for concurrent mutation; suitable for async single-process use.
- Not suitable for production multi-replica deployments.
Integration with mandate verification
Section titled “Integration with mandate verification”Every mandate verification path requires a RevocationStore:
TypeScript (@caracalai/transport-mcp):
import { authenticate } from '@caracalai/transport-mcp';import { InMemoryRevocationStore } from '@caracalai/revocation';
const revocations = new InMemoryRevocationStore();
const result = await authenticate(token, { issuer: 'http://sts:8080', audience: 'resource://api', revocations, // required});Python (caracalai_transport_mcp):
from caracalai_transport_mcp import authenticatefrom caracalai_revocation import InMemoryRevocationStore
revocations = InMemoryRevocationStore()
result = await authenticate( token, issuer='http://sts:8080', audience='resource://api', revocations=revocations, # required)Production: Redis-backed store
Section titled “Production: Redis-backed store”For multi-replica deployments, replace InMemoryRevocationStore with the Redis-backed implementation from @caracalai/revocation-redis or caracalai-revocation-redis. The Redis store also provides a RedisRevocationConsumer that subscribes to the caracal.sessions.revoke Redis stream and populates the store automatically from revocation events.
See Redis Connector for the full Redis revocation reference.
Revocation timing
Section titled “Revocation timing”The Gateway consumes the caracal.sessions.revoke stream and populates its revocation store within seconds of a session being revoked. Per-call mandates have a 15-minute TTL. A mandate issued before revocation completes will be rejected by the Gateway on the next request because the Gateway checks the sid claim against its revocation store on every request. Services behind the Gateway are therefore protected within the Gateway’s stream consumer latency (typically under 5 seconds). Services accessed directly — bypassing the Gateway — must maintain their own revocation store fed from the same stream to achieve sub-TTL enforcement.