How to check if a PINT (and its JWTs) has been revoked
JWTs issued by the have expiry times, but a user can also revoke a PINT before its expiry. When a PINT is revoked, all JWTs issued against it are invalidated. As a verifier, you should check revocation status to avoid accepting credentials that the user has withdrawn.
Authentication: API key via Authorization: Bearer header. This endpoint is deliberately permissive — any authenticated third-party caller with a valid SIS API key can check the status of any PINT they’ve been presented with. No specific scope is required.
The SRI contains colons that must be URL-encoded as %3A in the path. Most HTTP libraries handle this automatically with encodeURIComponent() or urllib.parse.quote().
true if the PINT is active and not expired; false if revoked or expired
reason
string or null
null when valid; "revoked" or "expired" when invalid
revoked_at
integer (epoch milliseconds) or null
Timestamp of when the PINT was revoked. null when the PINT is valid or has only expired without explicit revocation
_links.self
object
Link back to this status endpoint
_links.pint
object
Link to the full PINT resource
Timestamps default to epoch milliseconds. To receive ISO 8601 strings instead (e.g., "2026-02-13T11:30:00Z"), send the header X-Timestamp-Format: iso8601. This applies to revoked_at and any other _at fields in the response.
The revocation check endpoint is designed for low latency (< 100ms p99) and responses are already cached server-side for 30 seconds. You should still cache on your side to avoid excessive calls:Recommended approach: Cache the valid: true response for 30 seconds. This matches the server-side cache TTL and balances freshness (revocations propagate within 30s) with throughput.Do not cache indefinitely. A PINT that was valid at verification time may be revoked seconds later. The 30-second TTL provides a reasonable window.Cache valid: false longer. Once a PINT is revoked or expired, it doesn’t come back. You can cache negative results for the duration of the JWT’s remaining lifetime.
import { LRUCache } from "lru-cache";const revocationCache = new LRUCache<string, boolean>({ max: 10000, ttl: 30 * 1000, // 30 seconds for valid results});async function checkRevocationCached(pintUri: string): Promise<boolean> { const cached = revocationCache.get(pintUri); if (cached !== undefined) return cached; const isValid = await checkRevocation(pintUri); revocationCache.set(pintUri, isValid, { ttl: isValid ? 30 * 1000 : 300 * 1000, // 30s for valid, 5min for revoked }); return isValid;}
Always check on the first request for a given PINT in a session. After that, your cache handles subsequent checks within the TTL.Skip the check if you don’t have an SIS API key. JWT signature verification and expiry checking are still valid without revocation checking — you just won’t catch PINTs that were revoked before their natural expiry.