This document defines a JSON Web Signature (JWS) profile and abstract operations for representing, extending, validating, and merging a linear issuer-anchored history of JSON documents.

This document is an Editor's Draft and may change at any time. It is published for implementation and review feedback.

Introduction

A history consumer often needs to verify what an issuer intended at a particular time, even when snapshots are exchanged across distributed systems. This document specifies a JOSE-based format and deterministic operations that preserve a single conflict-free chain per issuer.

This specification is format- and algorithm-focused. API shapes used by a specific reference implementation are non-normative.

Conventions

The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, NOT RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in BCP 14 [[!RFC2119]] [[!RFC8174]] when, and only when, they appear in all capitals.

JSON is defined by [[!RFC8259]]. JWT and NumericDate are defined by [[!RFC7519]]. JWS and base64url handling in this specification follow [[!RFC7515]]. JWK and JOSE algorithm identifiers are defined by [[!RFC7517]] and [[!RFC7518]].

Core Terms

JSON Web History (JWH)
A linear, issuer-scoped chain of signed entries represented as a [=JWH snapshot=] or [=JWH string=].
JWH Entry
A JSON object payload that contains jti, iss, nbf, aft, and doc.
JWH Entry Token
A JWS Compact Serialization whose payload is a [=JWH entry=].
JWH Snapshot
A JSON array of [=JWH entry token=] values ordered from root to head.
JWH String
The JSON string serialization of a [=JWH snapshot=].
Document Schema
A deterministic schema fingerprint derived from a doc value by running [=derive document schema=].
Root Pointer
The string literal U+0000, used as aft in exactly one root [=JWH entry=].

JWS Profile

A [=JWH entry token=] MUST be a JWS Compact Serialization as defined by [[!RFC7515]].

The JWS Protected Header MUST contain:

The alg value MUST NOT be none. The signing or verification key used for processing a token MUST be a JWK compatible with the declared algorithm [[!RFC7517]] [[!RFC7518]].

Entry Model

Required members of a [=JWH entry=]
Member Type Requirements
jti string MUST be non-empty and unique within one [=JSON Web History=] [[!RFC7519]].
iss string MUST be non-empty and equal across all entries in one [=JSON Web History=] [[!RFC7519]].
nbf number MUST be a NumericDate [[!RFC7519]].
aft string MUST be either [=root pointer=] or the jti of exactly one earlier entry in the same history.
doc JSON value MUST be valid JSON and MUST be schema-compatible with the history's [=document schema=].

History Validity

A candidate [=JSON Web History=] is valid only if all of the following are true:

  1. It contains at least one [=JWH entry=].
  2. Exactly one entry has aft equal to [=root pointer=].
  3. Every non-root entry's aft references an existing jti in the same history.
  4. No two entries share the same jti.
  5. No parent entry has more than one child entry (that is, no forks are permitted).
  6. The chain formed by following aft links from root is acyclic and includes every entry exactly once.
  7. All entries have the same iss value.
  8. All entries' doc values are schema-compatible with the root entry's [=document schema=].

Abstract Operations

This specification defines the following abstract operations: [=derive document schema=], [=create a JWH entry=], [=tokenize a JWH entry=], [=parse a JWH entry token=], [=verify a JWH entry token=], [=validate a JWH snapshot=], [=start a JWH=], [=extend a JWH=], [=inspect a JWH=], and [=merge JWH snapshots=].

Derive Document Schema

This operation takes a JSON value doc and returns a schema fingerprint string.

  1. If doc is null, return "null".
  2. If doc is a boolean, number, or string, return the corresponding primitive type name.
  3. If doc is an array:
    1. Compute [=derive document schema=] for each element.
    2. Deduplicate and sort the resulting member schemas.
    3. Return "array<...>" containing the sorted member schemas joined by |.
  4. Otherwise doc is an object:
    1. Sort member keys lexicographically.
    2. For each key, compute JSON.stringify(key) + ':' + schema(value).
    3. Return "object{...}" containing sorted key-schema pairs joined by ,.

Create a JWH Entry

This operation takes iss, aft, and doc and returns a [=JWH entry=].

  1. Create a new JSON object entry.
  2. Set entry.jti to a new non-empty unique string.
  3. Set entry.iss to iss.
  4. Set entry.nbf to the current NumericDate.
  5. Set entry.aft to aft.
  6. Set entry.doc to doc.
  7. Return entry.

Tokenize a JWH Entry

This operation takes a [=JWH entry=] and signing key and returns a [=JWH entry token=].

  1. Construct a protected header containing typ set to JWT and alg set to the key algorithm.
  2. Serialize header and payload as UTF-8 JSON and base64url encode each value [[!RFC7515]].
  3. Sign the JWS Signing Input and produce a JWS Compact Serialization [[!RFC7515]].
  4. Return the resulting compact JWS string.

Parse a JWH Entry Token

This operation takes a [=JWH entry token=] and returns decoded header, payload, signature bytes, and signing input without validating the signature.

  1. Split token by . into three parts.
  2. If there are not exactly three parts, fail.
  3. Decode and parse protected header JSON.
  4. Require typ to equal JWT.
  5. Require alg to be a non-empty string.
  6. Decode and parse payload JSON as a [=JWH entry=].
  7. Decode signature bytes.
  8. Return parsed components.

Verify a JWH Entry Token

This operation takes a [=JWH entry token=] and verification key and returns the verified [=JWH entry=].

  1. Run [=parse a JWH entry token=].
  2. If header alg is none, fail.
  3. If the verification key declares an algorithm and it differs from header alg, fail.
  4. Verify JWS signature using [[!RFC7515]].
  5. If signature verification fails, fail.
  6. Return the parsed payload entry.

Validate a JWH Snapshot

This operation takes a [=JWH snapshot=] (or [=JWH string=]) and optionally a verification key and returns normalized history state.

  1. If input is a [=JWH string=], parse it as JSON array.
  2. If the snapshot is empty, fail.
  3. For each token:
    1. If a key is provided, run [=verify a JWH entry token=].
    2. Otherwise run [=parse a JWH entry token=].
    3. Apply the [=history validity=] requirements.
  4. Ensure original token order is root-to-head chain order; otherwise fail.
  5. Return normalized validated state.

Start a JWH

This operation takes iss, doc, and a signing key, and returns a [=JWH string=].

  1. Let entry be the result of [=create a JWH entry=] with aft set to [=root pointer=].
  2. Let token be the result of [=tokenize a JWH entry=] using entry and the signing key.
  3. Return JSON serialization of an array containing token.

Extend a JWH

This operation appends a new entry to a valid history and returns a [=JWH string=].

  1. Run [=validate a JWH snapshot=] on the input history.
  2. Let head be the last entry in validated chain order.
  3. Let incomingSchema be the result of [=derive document schema=] for the provided doc.
  4. If incomingSchema differs from the history [=document schema=], fail.
  5. Let entry be [=create a JWH entry=] with iss = head.iss and aft = head.jti.
  6. Let token be [=tokenize a JWH entry=] for entry.
  7. Append token to the snapshot.
  8. Return JSON serialization of the updated snapshot.

Inspect a JWH

This operation returns the effective [=JWH entry=] at time t.

  1. Run [=validate a JWH snapshot=].
  2. Discard entries with nbf > t.
  3. If no entry remains, fail.
  4. Return the entry with greatest nbf; break ties by lexicographically greatest jti.

Merge JWH Snapshots

This operation takes one or more [=JWH snapshot=] values and returns a single merged [=JWH snapshot=].

  1. If no input snapshots are provided, fail.
  2. Collect entries keyed by jti across all inputs.
  3. If two entries with the same jti differ in content, fail.
  4. If snapshots do not share one issuer and one [=document schema=], fail.
  5. Validate chain constraints from [=history validity=]; if any fails, fail.
  6. Order merged entries from root to head.
  7. Return tokens in that order.

Reference Implementation Mapping

A reference TypeScript implementation can expose these operations as top-level functions and optional convenience classes. Class names and method names are not normative requirements of this specification.

Security Considerations

Implementations MUST follow JWT best current practices from [[!RFC8725]]. In particular, implementations MUST enforce algorithm allowlists and MUST reject alg=none.

Consumers MUST verify every token signature before relying on entry contents. Treating unverified payload data as trusted history state can enable forgery.

Implementations SHOULD treat malformed or invalid histories as hard failures and MUST NOT auto-repair by dropping conflicting entries.

IANA Considerations

This document has no IANA actions.

This specification defines conformance requirements for producers and consumers of [=JSON Web History=] artifacts. Requirements are expressed in this document using the terminology defined in [[#conventions]].