{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://stella-ops.org/schemas/revocation-bundle.json", "title": "StellaOps Authority Revocation Bundle", "description": "Canonical representation of revoked tokens, clients, and principals distributed to offline mirrors.", "type": "object", "additionalProperties": false, "required": [ "schemaVersion", "issuer", "issuedAt", "sequence", "revocations" ], "properties": { "schemaVersion": { "type": "string", "pattern": "^1\\.0\\.[0-9]+$", "description": "SemVer of the bundle schema. Major version bumps indicate breaking changes." }, "issuer": { "type": "string", "format": "uri", "description": "Canonical issuer URL of the Authority instance producing the bundle." }, "bundleId": { "type": "string", "pattern": "^[a-f0-9]{16,64}$", "description": "Deterministic identifier for this bundle revision (e.g. SHA-256 hex)." }, "issuedAt": { "type": "string", "format": "date-time", "description": "UTC timestamp when the bundle was emitted." }, "validFrom": { "type": "string", "format": "date-time", "description": "UTC timestamp when consumers should begin enforcing entries." }, "expiresAt": { "type": "string", "format": "date-time", "description": "Optional expiry after which consumers must fetch a newer bundle." }, "sequence": { "type": "integer", "minimum": 0, "description": "Monotonic sequence number. Consumers MUST ignore bundles with lower sequence values." }, "signingKeyId": { "type": "string", "description": "Key identifier (kid) used for the detached JWS signature." }, "revocations": { "type": "array", "description": "Deterministically sorted revocation entries.", "items": { "$ref": "#/$defs/revocationEntry" } }, "metadata": { "type": "object", "description": "Additional producer metadata (operator, environment, export job id).", "additionalProperties": { "type": ["string", "number", "boolean", "null"] } } }, "$defs": { "revocationEntry": { "type": "object", "additionalProperties": false, "required": ["id", "category", "revokedAt"], "properties": { "id": { "type": "string", "minLength": 4, "description": "Primary identifier for the revoked entity (token id, subject id, client id, or key id)." }, "category": { "type": "string", "enum": ["token", "subject", "client", "key"], "description": "Scope of the revocation entry." }, "tokenType": { "type": "string", "enum": [ "access_token", "refresh_token", "authorization_code", "device_code" ], "description": "Token type impacted by the revocation (required when category == 'token')." }, "subjectId": { "type": "string", "description": "Subject identifier impacted (user, service account)." }, "clientId": { "type": "string", "description": "OAuth client identifier impacted." }, "reason": { "type": "string", "pattern": "^[a-z0-9_.-]{1,64}$", "description": "Reason code (e.g. compromised, rotation, policy)." }, "reasonDescription": { "type": "string", "maxLength": 256, "description": "Human-readable description for operator tooling." }, "revokedAt": { "type": "string", "format": "date-time", "description": "UTC timestamp when the entity was revoked." }, "effectiveAt": { "type": "string", "format": "date-time", "description": "UTC timestamp when revocation becomes effective (defaults to revokedAt)." }, "expiresAt": { "type": "string", "format": "date-time", "description": "Optional expiry after which the revocation no longer applies." }, "scopes": { "type": "array", "items": { "type": "string" }, "uniqueItems": true, "description": "Scoped permissions affected (for token revocations)." }, "fingerprint": { "type": "string", "pattern": "^[A-Fa-f0-9]{64}$", "description": "SHA-256 hash of the revoked credential (optional)." }, "metadata": { "type": "object", "description": "Additional structured metadata to assist consumers (e.g. audit id).", "patternProperties": { "^[a-zA-Z0-9_.-]{1,64}$": { "type": ["string", "number", "boolean", "null"] } }, "additionalProperties": false } }, "allOf": [ { "if": { "properties": { "category": { "const": "token" } } }, "then": { "required": ["tokenType", "clientId"] } }, { "if": { "properties": { "category": { "const": "subject" } } }, "then": { "required": ["subjectId"] } }, { "if": { "properties": { "category": { "const": "client" } } }, "then": { "required": ["clientId"] } } ] } } }