@owf/token-status-list
Implementation of Token Status List (draft-ietf-oauth-status-list) with core bitstring handling, JWT transport, and CWT/CBOR transport — all in one package.
Features
- Core StatusList: Variable bit-width (1/2/4/8-bit) status entries with deflate compression
- Random index assignment: Deterministic, non-repeating index allocation from a private seed
- JWT transport: Create and decode Status List Tokens in JWT format
- CWT transport: Create and decode Status List Tokens in CWT/CBOR format
- Referenced Token support: Extract status claims from both JWT and CWT referenced tokens
- COSE algorithm constants: Standard IANA COSE algorithm identifiers
Installation
npm install @owf/token-status-list
Usage
Core — create and query a status list
import { StatusList, StatusTypes } from '@owf/token-status-list'
// Create a list of 100 000 entries at 1 bit each
const list = new StatusList(new Array(100_000).fill(0), 1)
// Mark some entries
list.setStatus(42, StatusTypes.INVALID)
list.setStatus(99, StatusTypes.INVALID)
// Query a status
list.getStatus(42) // 1 (INVALID)
list.getStatus(0) // 0 (VALID)
// Compress / decompress for transport
const compressed = list.compressStatusListToBytes()
const restored = StatusList.decompressStatusListFromBytes(compressed, 1)
Randomly assign status-list indices
Use a private, persisted seed to assign each index exactly once in a deterministic random order:
import { hasher } from '@owf/crypto'
import { StatusListIndexAllocator, createStatusListIndexAllocator } from '@owf/token-status-list'
// The package never touches a global Web Crypto implementation: pass the
// hasher that expands the seed. It must compute SHA-256 for the permutation to
// be reproducible across restarts.
const ctx = { hasher }
const allocator = await createStatusListIndexAllocator({ length: 1_000_000, seed }, ctx)
const index = allocator.next()
const state = allocator.getState() // persist with the allocation counter
// Resume later — the persisted state is accepted as-is
const resumed = await StatusListIndexAllocator.create(state, ctx)
The seed must remain private to prevent predicting future assignments. Persist the allocator state and advance it atomically when issuing tokens; database transactions are the caller's responsibility.
Known limitation
The compressed status-list format stores statuses in whole bytes, but does not
store the original number of status entries. For example, three 1-bit entries
are encoded in one byte, so decompressing that byte produces eight byte-aligned
entries. The first three status values are preserved, but the original list
length cannot be reconstructed from bits and lst alone.
This is allowed by the specification: Section 4.1 permits the byte array to be
the size of the number of Referenced Tokens multiplied by bits divided by 8,
or greater. Section 13.4 recommends byte-aligned list sizes but does not require
them. Callers that need the original logical length must preserve it separately.
JWT transport — issue and read a Status List Token
import { StatusList, createHeaderAndPayload, getListFromStatusListJWT } from '@owf/token-status-list'
const list = new StatusList(new Array(100_000).fill(0), 1)
list.setStatus(42, 1)
// Build header + payload (sign with your own JOSE library)
const { header, payload } = createHeaderAndPayload(
list,
{ iss: 'https://issuer.example', sub: 'https://issuer.example/statuslists/1', iat: Math.floor(Date.now() / 1000) },
{ alg: 'ES256', typ: '' },
)
// Later — decode the list back from a JWT string
const decoded = getListFromStatusListJWT(jwt)
decoded.getStatus(42) // 1
JWT transport — read a referenced token's status entry
import { getStatusListFromJWT } from '@owf/token-status-list'
const entry = getStatusListFromJWT(referencedTokenJWT)
// entry.idx — index into the status list
// entry.uri — URI of the Status List Token
CWT transport — issue and read a Status List Token
import {
StatusList,
COSEAlgorithms,
createStatusListCWTPayload,
createStatusListCWTHeader,
encodeCWTPayload,
decodeCWTPayload,
} from '@owf/token-status-list'
const list = new StatusList(new Array(100_000).fill(0), 1)
list.setStatus(42, 1)
// Build CWT claims and header (sign with your own COSE library)
const payload = createStatusListCWTPayload(list, 'https://issuer.example/statuslists/1', Math.floor(Date.now() / 1000))
const header = createStatusListCWTHeader(COSEAlgorithms.ES256, 'key-id-1')
// Encode to CBOR
const cborPayload = encodeCWTPayload(list, 'https://issuer.example/statuslists/1', Math.floor(Date.now() / 1000))
// Decode
const { subject, issuedAt, statusList } = decodeCWTPayload(cborPayload)
statusList.getStatus(42) // 1
CWT transport — referenced token status claim
import { createCWTStatusClaim, encodeCWTStatusClaim, decodeCWTStatusClaim } from '@owf/token-status-list'
// Create
const claim = createCWTStatusClaim(42, 'https://issuer.example/statuslists/1')
// Encode/decode via CBOR
const encoded = encodeCWTStatusClaim(42, 'https://issuer.example/statuslists/1')
const decoded = decodeCWTStatusClaim(encoded)
// decoded.idx === 42, decoded.uri === '...'
API
Core
| Export | Description |
|---|---|
StatusList |
Main class — construct, get/set status, compress/decompress |
createStatusListIndexAllocator |
Create a seeded allocator that returns each status-list index once |
StatusListIndexAllocator |
Allocator class with next(), remaining(), and getState() |
StatusListIndexAllocatorState |
Restorable allocator state type |
SLException |
Error class thrown by status-list operations |
StatusTypes |
Constants: VALID, INVALID, SUSPENDED, etc. |
MediaTypes |
MIME types for JWT and CWT status list tokens |
BitsPerStatus |
Type: 1 | 2 | 4 | 8 |
StatusListEntry |
Type: { idx: number; uri: string } |
JWT Transport
| Export | Description |
|---|---|
createHeaderAndPayload |
Build JWT header + payload from a StatusList |
getListFromStatusListJWT |
Decode a StatusList from a JWT string |
getStatusListFromJWT |
Extract StatusListEntry from a referenced token JWT |
JWT_STATUS_LIST_TYPE |
"statuslist+jwt" |
JWTClaimNames |
Claim name constants |
CWT Transport
| Export | Description |
|---|---|
createStatusListCWTPayload |
Build CWT claims from a StatusList |
createStatusListCWTHeader |
Build COSE protected header |
encodeCWTPayload / decodeCWTPayload |
CBOR encode/decode full payload |
encodeStatusListToCBOR / decodeStatusListFromCBOR |
CBOR encode/decode the status list only |
createCWTStatusClaim |
Build a referenced-token status claim object |
encodeCWTStatusClaim / decodeCWTStatusClaim |
CBOR encode/decode a status claim |
getListFromStatusListCWT |
Extract StatusList from CWT payload bytes |
getStatusListFromCWT |
Extract StatusListEntry from CWT payload bytes |
COSEAlgorithms |
IANA COSE algorithm identifiers (ES256, ES384, EdDSA, …) |
CWT_STATUS_LIST_TYPE |
"application/statuslist+cwt" |
CWTClaimKeys / CWTStatusListKeys / CWTStatusListInfoKeys / COSEHeaderKeys |
Numeric/string key constants |