JCS canonicalization

JCS (JSON Canonicalization Scheme, RFC 8785) defines a single, deterministic byte representation for any JSON document, fixing key order, number formatting, and escaping. Signatures cover bytes, not meanings, so two logically identical JSON payloads with different byte forms verify differently; canonicalization ensures signer and verifier hash the same bytes.

Canonicalization is only needed where the signature covers a structure rather than a byte string. A protocol that signs the raw request body and asks verifiers to check the bytes they received avoids the problem entirely, which is usually the simpler design.

Where a document is stored, re-indexed or round-tripped through a database before verification, key order is not preserved and canonicalization becomes the only way signer and verifier agree on what was signed.

The rule of thumb is to sign bytes wherever the protocol allows it. A signature over the raw request body, verified against the bytes as received, has no canonicalization problem at all, and it removes an entire class of interoperability failure between implementations that serialize JSON differently.

Where the artifact is a document rather than a message, that option disappears. A credential stored in a database, re-indexed, or reconstructed from parsed fields will not preserve key order or number formatting, so signer and verifier need a shared rule for producing the same bytes from the same structure, which is what the scheme specifies.

Number formatting is the detail that causes the most surprise, because JSON parsers differ in how they render values that round-trip through a floating-point type. The canonicalization rules fix that, and the practical consequence is that a value which looks identical in two documents can still hash differently if either side has been through a parser that changed its representation. Verifying an artifact that a hybrid signature covers means both layers depend on getting this right.

A credential presented as an SD-JWT raises the same question about which bytes the signature covers.

PasskeyBridge verifies identity signals like these inside the request, with zero PII stored. See how the platform works or test the live API.