← Back to list

The Structure and Implementation of StatusList in the TSL Specification

Takahiko Kawasaki · 2026-01-06 01:37 · 1 claps · 5.3 min read
#token-status-list #verifiable-credentials #tsl #jwt #cwt
Open on Medium ↗

The Structure and Implementation of StatusList in the TSL Specification

Introduction

The **Token Status List (TSL**) specification is nearing completion.

This specification is designed to handle status information (such as valid or invalid) for various token types based on JOSE and COSE, including JWT, SD-JWT VC, CWT, and ISO mdoc.

To efficiently represent the status of a large number of tokens, statuses are encoded as a bit array and compressed using DEFLATE.

The TSL specification defines a data structure called StatusList to represent this list of statuses. In this article, we take a closer look at the StatusList.

Structure of the StatusList

Regardless of whether the format is JSON or CBOR, a StatusList has the following properties:

  • bits — REQUIRED. The number of bits used to represent a single status. One of 1, 2, 4, or 8.
  • lst — REQUIRED. A DEFLATE-compressed representation of the status values expressed as a byte array. In CBOR, it is represented as a byte array; in JSON, it is represented as a base64url-encoded string.
  • aggregation_uri — OPTIONAL. A location from which a list of URIs that publish Status List Tokens can be obtained.

Below are examples of StatusList objects in JSON format, excerpted from the specification.

{
  "bits": 1,
  "lst": "eNrbuRgAAhcBXQ"
}
{
  "bits": 2,
  "lst": "eNo76fITAAPfAgc"
}

The bits property represents the number of bits used to encode a single status, and its possible values are 1, 2, 4, or 8. When the number of bits is 1, up to 2¹ = 2 different statuses can be represented, for example, “valid” and “invalid.” When the number of bits is 2, up to 2² = 4 statuses can be represented; with 4 bits, up to 2⁴ = 16 statuses; and with 8 bits, up to 2⁸ = 256 statuses can be represented.

The lst property contains the DEFLATE-compressed byte array that enumerates the set of statuses. In the CBOR format, the result of the DEFLATE compression is stored directly as a byte array, whereas in the JSON format, it is base64url-encoded and represented as a string.

For example, suppose the number of bits used to represent a status is set to 1, and the statuses of 16 tokens are as follows:

| Index | Status  | Value |
|-------+---------+-------|
|   0   | INVALID |   1   |
|   1   |  VALID  |   0   |
|   2   |  VALID  |   0   |
|   3   | INVALID |   1   |
|   4   | INVALID |   1   |
|   5   | INVALID |   1   |
|   6   |  VALID  |   0   |
|   7   | INVALID |   1   |
|   8   | INVALID |   1   |
|   9   | INVALID |   1   |
|  10   |  VALID  |   0   |
|  11   |  VALID  |   0   |
|  12   |  VALID  |   0   |
|  13   | INVALID |   1   |
|  14   |  VALID  |   0   |
|  15   | INVALID |   1   |

If these are packed as shown in the following figure, the resulting byte array is [0xB9, 0xA3].

Statuses represented as a byte array with bits=1

Statuses represented as a byte array with bits=1

This byte array is then compressed using DEFLATE and set as the value of lst.

Similarly, suppose the number of bits used to represent a status is 2, and the statuses of 12 tokens are as follows:

| Index | Status |
|-------+--------|
|   0   |   01   |
|   1   |   10   |
|   2   |   00   |
|   3   |   11   |
|   4   |   00   |
|   5   |   01   |
|   6   |   00   |
|   7   |   01   |
|   8   |   01   |
|   9   |   10   |
|  10   |   11   |
|  11   |   11   |

When these statuses are packed as illustrated in the following figure, the resulting byte array is [0xC9, 0x44, 0xF9].

Statuses represented as a byte array with bits=2

Statuses represented as a byte array with bits=2

This byte array is then compressed using DEFLATE and set as the value of lst.

Implementation of the StatusList

The CBOR library **authlete/cbor (for Java), which [Authlete](https://www.authlete.com/)** publishes as open source, includes a class named StatusList for representing a StatusList in the com.authlete.cbor.tsl package starting from version 1.21.

The constructor of this StatusList class takes the following arguments: int bits, byte[] lst, and String aggregationUri.

public StatusList(int bits, byte[] lst, String aggregationUri)

However, preparing the value of lst in the first place is cumbersome, so the path to calling this constructor is not so easy. To address this, a utility class named StatusListBuilder is provided for creating instances of the StatusList class.

The usage of StatusListBuilder is as follows:

  1. Choose the number of bits used to represent each status from among 1, 2, 4, or 8.
  2. Create a StatusListBuilder instance by passing the chosen bit size to its constructor.
  3. Call the valueAt method as many times as needed to set individual status values.
  4. If you want to set aggregation_uri, call the aggregationUri method.
  5. If you want to reserve capacity beyond the number of statuses automatically expanded by the indices specified via valueAt, call the capacity method.
  6. Finally, call the build method to create a StatusList instance.

For example, to create a StatusList that contains the following set of statuses listed in Section 4.1. Compressed Byte Array of the TSL specification,

status[ 0] = 0b1
status[ 1] = 0b0
status[ 2] = 0b0
status[ 3] = 0b1
status[ 4] = 0b1
status[ 5] = 0b1
status[ 6] = 0b0
status[ 7] = 0b1
status[ 8] = 0b1
status[ 9] = 0b1
status[10] = 0b0
status[11] = 0b0
status[12] = 0b0
status[13] = 0b1
status[14] = 0b0
status[15] = 0b1

you can write the code as follows:

// Number of bits used to represent a status
int bits = 1;

// Create a StatusListBuilder instance by passing the number
// of bits to the constructor
StatusListBuilder builder = new StatusListBuilder(bits);

// Set status values
builder.valueAt(StatusTypeValue.INVALID,  0);
builder.valueAt(StatusTypeValue.VALID,    1);
builder.valueAt(StatusTypeValue.VALID,    2);
builder.valueAt(StatusTypeValue.INVALID,  3);
builder.valueAt(StatusTypeValue.INVALID,  4);
builder.valueAt(StatusTypeValue.INVALID,  5);
builder.valueAt(StatusTypeValue.VALID,    6);
builder.valueAt(StatusTypeValue.INVALID,  7);
builder.valueAt(StatusTypeValue.INVALID,  8);
builder.valueAt(StatusTypeValue.INVALID,  9);
builder.valueAt(StatusTypeValue.VALID,   10);
builder.valueAt(StatusTypeValue.VALID,   11);
builder.valueAt(StatusTypeValue.VALID,   12);
builder.valueAt(StatusTypeValue.INVALID, 13);
builder.valueAt(StatusTypeValue.VALID,   14);
builder.valueAt(StatusTypeValue.INVALID, 15);

// Create a StatusList instance
StatusList statusList = builder.build();

StatusList is a subclass of CBORItem, so you can use the encodeToHex() method to represent it in hexadecimal,

System.out.println(statusList.encodeToHex());
a2646269747301636c73744a78dadbb918000217015d

or use the toString() or prettify() methods to represent it in CBOR Diagnostic Notation.

System.out.println(statusList.prettify());
{
  "bits": 1,
  "lst": h'78dadbb918000217015d'
}

By the way, if you convert the byte array to a base64url string using the Base64UrlAdapter introduced in GSON: Converting Byte Arrays to and from Base64URL Strings (or by any other method—what matters is simply converting the lst value from a byte array to a base64url string),

// Create a Gson instance with Base64UrlAdapter enabled
Gson gson = new GsonBuilder()
        .registerTypeAdapter(byte[].class, new Base64UrlAdapter())
        .setPrettyPrinting()
        .create();

// Convert the CBORItem into a general-purpose Java object using
// the parse() method
Object statusListObject = statusList.parse();

// Convert to JSON
String json = gson.toJson(statusListObject);

// Output the JSON
System.out.println(json);

you can generate JSON that complies with the requirements defined in Section 4.2. Status List in JSON Format of the TSL specification.

{
  "bits": 1,
  "lst": "eNrbuRgAAhcBXQ"
}

Conclusion

When you need to work with CBOR in Java, please give the **authlete/cbor** library a try. Authlete itself also uses the authlete/cbor library in its implementation of OpenID for Verifiable Credential Issuance 1.0 (OID4VCI).

We also operate a website called **CBOR Zone**, which allows you to convert CBOR data between the following formats. It’s quite handy, so be sure to check it out!

  • Hexadecimal
  • Base64
  • Base64URL
  • Diagnostic Notation

CBOR Zone (https://cbor.zone/)

CBOR Zone (https://cbor.zone/)

(This screenshot shows the conversion from the hexadecimal representation of a StatusList to Diagnostic Notation.)


메타데이터
post_id
93d1c019f9e4
slug
statuslist-93d1c019f9e4
url
https://medium.com/@darutk/statuslist-93d1c019f9e4
canonical_url
https://medium.com/@darutk/statuslist-93d1c019f9e4
author_url
https://medium.com/@darutk
status
ok
fetched_at
2026-06-16 19:09:56