Key Verification & Caching

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.

3-Tier Caching Architecture

graph TD
    REQ["Verification Request"] --> T1
    T1["Tier 1: In-Memory Failure Cache<br/>Prevents repeated requests to unreachable instances<br/>TTL 5 minutes for network errors, 1 hour for persistent errors<br/>LRU eviction when capacity exceeded"]
    T1 -->|"cache miss or expired"| T2["Tier 2: SQLite Key Cache<br/>Persistent cache of successful key fetches<br/>Keyed by issuer and key_id<br/>Stores public key plus expiration timestamp<br/>If valid and not expired, verify signature immediately"]
    T2 -->|"cache miss or expired"| T3["Tier 3: HTTP Fetch from Remote<br/>GET https://cl-o.ISSUER/api/me<br/>Find matching key by key_id<br/>On success, cache in SQLite and clear failure cache<br/>On failure, record in failure cache"]

Failure Types and TTLs

Error Type TTL Reason
Network timeout 5 minutes May recover quickly
Connection refused 5 minutes Server may restart
404 Not Found 1 hour Key doesn’t exist
403 Forbidden 1 hour Permission denied
Parse error 1 hour Invalid response format

Verification Flow

flowchart TD
    A["Decode JWT without verifying<br/>to extract issuer and key_id"] --> B{"Failure cache hit<br/>and not expired?"}
    B -->|"yes"| E1["Error: CachedFailure"]
    B -->|"no"| C{"SQLite key cache hit<br/>and not expired?"}
    C -->|"yes"| V["verify_signature with cached public key"]
    C -->|"no"| F["GET https://cl-o.ISSUER/api/me"]
    F -->|"request failed"| E2["Record failure<br/>Error: KeyFetchFailed"]
    F -->|"key_id not in response"| E3["Record failure<br/>Error: KeyNotFound"]
    F -->|"key found"| S["Store key in SQLite cache<br/>Clear failure cache"]
    S --> V

See Also