When receiving federated actions, the server must verify the JWT signature using the issuer’s public key. This involves a 3-tier caching strategy to balance security with performance.
┌─────────────────────────────────────────────────────────────────┐
│ Verification Request │
└───────────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Tier 1: In-Memory Failure Cache │
│ ├─ Purpose: Prevent repeated requests to unreachable instances │
│ ├─ TTL (network errors): 5 minutes │
│ ├─ TTL (persistent errors): 1 hour │
│ └─ LRU eviction when capacity exceeded │
└───────────────────────────────┬─────────────────────────────────┘
│ (cache miss or expired)
▼
┌─────────────────────────────────────────────────────────────────┐
│ Tier 2: SQLite Key Cache │
│ ├─ Purpose: Persistent cache of successful key fetches │
│ ├─ Key: (issuer, key_id) │
│ ├─ Stores: public key + expiration timestamp │
│ └─ If valid & not expired: verify signature immediately │
└───────────────────────────────┬─────────────────────────────────┘
│ (cache miss or expired)
▼
┌─────────────────────────────────────────────────────────────────┐
│ Tier 3: HTTP Fetch from Remote │
│ ├─ Endpoint: GET https://cl-o.{issuer}/api/me │
│ ├─ Find matching key by key_id │
│ ├─ On success: cache in SQLite, clear failure cache │
│ └─ On failure: record in failure cache │
└─────────────────────────────────────────────────────────────────┘
verify_action_token(token):
1. Decode JWT without verifying (extract issuer, key_id)
2. Check failure cache:
if failure_cache.has(issuer, key_id) and not expired:
return Error(CachedFailure)
3. Check SQLite cache:
if key_cache.has(issuer, key_id):
key = key_cache.get(issuer, key_id)
if key.expires_at > now:
return verify_signature(token, key.public_key)
4. Fetch from remote:
response = HTTP GET https://cl-o.{issuer}/api/me
if error:
failure_cache.record(issuer, key_id, error_type)
return Error(KeyFetchFailed)
public_key = find_key_by_id(response.keys, key_id)
if not found:
failure_cache.record(issuer, key_id, NotFound)
return Error(KeyNotFound)
key_cache.store(issuer, key_id, public_key)
failure_cache.clear(issuer, key_id)
return verify_signature(token, public_key)