JSON-LD VCs are NOT “just JSON”

Markus Sabadello
4 min readOct 14, 2023

--

Experiments with JSON-LD VC payloads secured by JWS vs. Data Integrity
Detailed results: https://github.com/peacekeeper/json-ld-vcs-not-just-json

In the world of Verifiable Credentials (VCs), it can be hard to keep track of various evolving formats and data models. A potpourri of similar-sounding terms can be found in specification documents, mailing lists and meeting notes, such as VCDM, VC-JWT, VC-JWS, JWT VCs, SD-JWT, SD-JWT-VC, SD JWS, VC JOSE COSE, SDVC, JsonWebSignature2020, etc.

Also, statements like the following can frequently be found in discussions:

  • “Can we make @context optional. It’s simpler and not always needed.”
  • “If you don’t want to use @context and just ignore it, you could.”
  • “You can secure a JSON-LD VC using JWT.”
  • “You can use SD-JWT for any JSON payload, including JSON-LD.”
  • “JSON-LD is JSON.”

One concrete question related to this is what it means if a VC using the JSON-LD-based W3C VC Data Model is secured by proof mechanisms that were designed without JSON-LD in mind.

Experimentation

To explore this, I conducted two experiments to describe what happens if you take a JSON-LD document based on the W3C VC Data Model, and you secure it once with JWS, and once with Data Integrity. The former signs the document, while the latter signs the underlying RDF graph of the document. The part where this gets interesting is the JSON-LD @context. For JWS, only the contents of the document matter. For Data Integrity, the contents of the @context matter as well. The two proof mechanisms have a rather different understanding of the “payload” that is to be secured.

Experiment #1: Data Integrity changes, JWS doesn’t

In the first experiment, we start with a JSON-LD document named example1a.input. This document references a JSON-LD @context https://example.com/context1/, and the contents of that @context are as in the file context1a.jsonld.

In a subsequent variation of this, we start with another JSON-LD document named example1b.input, which is equivalent to the above example1a.input. This document also references the same JSON-LD @context https://example.com/context1/, but now, the contents of that @context are as in the file context1b.jsonld, which is different from the file context1a.jsonld that was used above.

The result: If the contents of the JSON-LD @context change, even if the JSON-LD document stays the same, the Data Integrity signature also changes, whereas the JWS signature doesn’t change. This also means that verifying a Data Integrity signature would fail, whereas verifying a JWS signature would succeed.

Experiment #2: JWS changes, Data Integrity doesn’t

In the second experiment, we start with a JSON-LD document named example2a.input. This document references a JSON-LD @context https://example.com/context2a/, and the contents of that @context are as in the file context2a.jsonld.

In a subsequent variation of this, we start with another JSON-LD document named example2b.input, which is different from the above example2a.input. The difference is that the first document used the term “givenName”, while the second document uses the term “firstName”. The second document references a different JSON-LD @context https://example.com/context2b/, and the contents of that @context are as in the file context2b.jsonld, which is different from the file context2a.jsonld that was used above. The difference is that the first @context defines the term “givenName”, while the second @context defines the term “firstName”, however, they define them using the same URI, i.e. with equivalent semantics.

The result: Despite the fact that the JSON-LD document changes, the Data Integrity signature doesn’t change, whereas the JWS signature changes. This is because Data Integrity “understands” that even though the document has changed, the semantics of the RDF graph are still the same. JWS on the other hand “sees” only the JSON-LD document, not the semantics behind it. This also means that verifying a Data Integrity signature would succeed, whereas verifying a JWS signature would fail.

Conclusion

Depending on your perspective, you could interpret the results in different ways. You could call Data Integrity insecure, since it depends on information outside the JSON document. You could also call JWS insecure, since it fails to secure the JSON-LD data model.

The real point of this article is however NOT to say that any of the mentioned data models or proof mechanisms are inherently insecure, but rather to raise awareness of the nuances. To say “JSON-LD is JSON” is correct on the document layer, and wrong on the data model layer. Certain combinations of data models and proof mechanisms can lead to surprising results, if they are not understood properly.

--

--