Publish and maintain a status list: revocation for mandates

A mandate without revocation is dangerous: if an agent is compromised, its mandate stays valid until it expires. A status list solves this. This guide shows structure, signature, publication and maintenance.

Key points

  • A status list is a compressed, signed bit string with one entry per mandate.
  • On revocation, the bit is set, the list re-signed and published immediately.
  • If the list is missing at verification, the verdict stays indeterminate under the fail-closed principle.

Understand the structure

A status list is a bit string: every mandate receives an index at issuance, and its status sits at that position, with one bit 0 for valid and 1 for revoked, and with two bits additionally 2 for suspended. The bit string is compressed with DEFLATE in the ZLIB format, Base64url-encoded and published as the status_list claim in a signed JWT.

Create and sign the list

The following script creates a list with 1,024 entries, revokes the entry with index 3 and signs the list with the key from the JWKS guide:

import { deflateSync } from "node:zlib";
import { createPrivateKey, sign } from "node:crypto";
import { readFileSync, writeFileSync } from "node:fs";

const bits = 1, size = 1024;
const list = new Uint8Array((size * bits) / 8);
const revoke = (i) => { list[i >> 3] |= 1 << (i & 7); };
revoke(3);

const b64u = (b) => Buffer.from(b).toString("base64url");
const header = { alg: "ES256", typ: "statuslist+jwt", kid: "issuer-2026-10" };
const payload = {
  sub: "https://example.com/status/1",
  iat: Math.floor(Date.now() / 1000),
  ttl: 3600,
  status_list: { bits, lst: b64u(deflateSync(list)) },
};
const input = b64u(JSON.stringify(header)) + "." + b64u(JSON.stringify(payload));
const key = createPrivateKey(readFileSync("private.pem"));
const signature = sign("sha256", Buffer.from(input), { key, dsaEncoding: "ieee-p1363" });
writeFileSync("status-list.jwt", input + "." + b64u(signature));

Within each byte, bits are counted from the least significant bit, as the specification requires.

Check the result

Paste the file created into the status list decoder and enter index 3. The decoder shows 1,024 entries and the value 1 at index 3. A verifying party checks the signature with your JWKS.

Let mandates refer to the list

In every mandate, enter the status_list claim under status, with idx, the mandate's index, and uri, the list's address. Assign indexes randomly rather than sequentially, so nothing about the order of issuance can be read from the index.

Publish and update

Serve the list at the address in uri and renew it regularly with a new iat; the ttl claim tells verifying parties how long they may use a loaded version. On revocation, set the bit, sign again and publish immediately. Verifying parties provide the current version; if it is missing, the verdict stays indeterminate under the fail-closed principle.

Troubleshooting

If verification reports status_list_invalid, the list has expired, is wrongly signed or is not readable; the status list decoder shows whether it can be unpacked. If a revoked mandate still shows as valid, check whether the index in the mandate matches the position set and whether the verifying party has provided the current version.

Frequently asked questions

How large should a status list be?

Large enough that the number of issued mandates cannot be inferred from the number of entries, for example a few thousand entries per list.

Can I reactivate a revoked mandate?

With two bits per entry, a mandate can be suspended and later released again. A revocation, by contrast, should be final.

How often should I republish the status list?

Regularly, even without changes, so iat stays current, and immediately on every revocation. The interval depends on ttl and on the risk.

Can a status list contain mandates from different issuers?

No. Each list belongs to one issuer and is signed with its key; every mandate refers to its issuer's list.

Sources

  1. IETF: Token Status List: https://datatracker.ietf.org/doc/draft-ietf-oauth-status-list/
  2. RFC 1950: ZLIB Compressed Data Format: https://www.rfc-editor.org/rfc/rfc1950