CINXE.COM
IPLD ♦ DAG-JOSE Specification
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="/css/layout.css?1718759055581"> <link rel="stylesheet" href="/css/nav.css?1718759055581"> <link rel="stylesheet" href="/css/style.css?1718759055581"> <link rel="stylesheet" href="/css/prismjs@1.24-themes-prism.css"> <title>IPLD ♦ DAG-JOSE Specification</title> </head> <body> <header> <div class="sidebar-button" onclick="document.getElementById('sidebar').classList.toggle('sidebar-open')"> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"> <path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path> </svg> </div> <a href="/" class="logo">IPLD</a> <aside id=breadcrumbs> <ul> <li><a href="/specs">specs</a></li> <li><a href="/specs/codecs">codecs</a></li> <li><a href="/specs/codecs/dag-jose">dag-jose</a></li> <li><a href="/specs/codecs/dag-jose/spec/">spec</a></li> </ul> </aside> </header> <aside id=sidebar> <nav> <ul> <li> <a href="/docs/">Docs</a><ul> <li> <a href="/docs/intro/">Intro</a><ul> <li> <a href="/docs/intro/hello-world/">Hello, World</a></li> <li> <a href="/docs/intro/primer/">The Brief Primer</a></li> <li> <a href="/docs/intro/ecosystem/">InterPlanetary Ecosystem Overview</a></li> <li> <a href="/docs/intro/community/">Finding Community</a></li></ul></li> <li> <a href="/docs/motivation/">Motivation</a><ul> <li> <a href="/docs/motivation/benefits-of-content-addressing/">Benefits of Content Addressing</a></li> <li> <a href="/docs/motivation/data-to-data-structures/">From Data to Data Structures</a></li></ul></li> <li> <a href="/docs/codecs/">Codecs</a><ul> <li> <a href="/docs/codecs/known/">Known Codecs</a><ul> <li> <a href="/docs/codecs/known/dag-cbor/">DAG-CBOR</a></li> <li> <a href="/docs/codecs/known/dag-json/">DAG-JSON</a></li> <li> <a href="/docs/codecs/known/dag-pb/">DAG-PB</a></li></ul></li></ul></li> <li> <a href="/docs/data-model/">Data Model</a><ul> <li> <a href="/docs/data-model/node/">Nodes</a></li> <li> <a href="/docs/data-model/kinds/">Kinds</a></li> <li> <a href="/docs/data-model/pathing/">Pathing</a></li> <li> <a href="/docs/data-model/traversal/">Traversal</a></li></ul></li> <li> <a href="/docs/advanced-data-layouts/">Advanced Data Layouts</a><ul> <li> <a href="/docs/advanced-data-layouts/intro/">Intro to ADLs</a></li> <li> <a href="/docs/advanced-data-layouts/naming/">ADL Naming</a></li> <li> <a href="/docs/advanced-data-layouts/signalling/">Signalling ADLs</a></li> <li> <a href="/docs/advanced-data-layouts/dynamic-loading/">Dynamic Loading</a></li> <li> <a href="/docs/advanced-data-layouts/known/">Known ADLs</a></li></ul></li> <li> <a href="/docs/schemas/">Schemas</a><ul> <li> <a href="/docs/schemas/intro/">Introduction</a><ul> <li> <a href="/docs/schemas/intro/compare/">compare</a></li> <li> <a href="/docs/schemas/intro/goals/">Goals</a></li> <li> <a href="/docs/schemas/intro/feature-summary/">Feature Summary</a></li></ul></li> <li> <a href="/docs/schemas/features/">Features</a><ul> <li> <a href="/docs/schemas/features/typekinds/">Type Kinds</a></li> <li> <a href="/docs/schemas/features/representation-strategies/">Representation Strategies</a></li> <li> <a href="/docs/schemas/features/links/">Links</a></li> <li> <a href="/docs/schemas/features/indicating-adls/">Using ADLs in Schemas</a></li></ul></li> <li> <a href="/docs/schemas/using/">Using Wisely</a><ul> <li> <a href="/docs/schemas/using/authoring-guide/">Authoring Guide</a></li> <li> <a href="/docs/schemas/using/migrations/">Migrations</a></li></ul></li></ul></li> <li> <a href="/docs/synthesis/">Synthesis</a><ul> <li> <a href="/docs/synthesis/gtd/">Getting Things Done</a></li> <li> <a href="/docs/synthesis/building-in-alignment/">Building in Alignment</a></li> <li> <a href="/docs/synthesis/how-ipfs-web-gateways-work/">How IPFS Web Gateways Work</a></li> <li> <a href="/docs/synthesis/encryption/">Working With Encryption</a></li></ul></li></ul></li> <li> <a href="/specs/">Specs</a><ul> <li> <a href="/specs/about/">About the Specifications</a></li> <li> <a href="/specs/codecs/">Codecs</a><ul> <li> <a href="/specs/codecs/dag-cbor/">DAG-CBOR</a><ul> <li> <a href="/specs/codecs/dag-cbor/fixtures/">DAG-CBOR Test Fixtures</a><ul> <li> <a href="/specs/codecs/dag-cbor/fixtures/cross-codec/">cross-codec</a></li></ul></li> <li> <a href="/specs/codecs/dag-cbor/spec/">Spec</a></li></ul></li> <li> <a href="/specs/codecs/dag-cosmos/">DAG-COSMOS</a><ul> <li> <a href="/specs/codecs/dag-cosmos/basic_types/">basic_types</a></li> <li> <a href="/specs/codecs/dag-cosmos/cosmos_state/">cosmos_state</a></li> <li> <a href="/specs/codecs/dag-cosmos/crypto_types/">crypto_types</a></li> <li> <a href="/specs/codecs/dag-cosmos/tendermint_chain/">tendermint_chain</a></li> <li> <a href="/specs/codecs/dag-cosmos/typed_protobuf/">typed_protobuf</a></li></ul></li> <li> <a href="/specs/codecs/dag-eth/">DAG-ETH</a><ul> <li> <a href="/specs/codecs/dag-eth/basic_types/">basic_types</a></li> <li> <a href="/specs/codecs/dag-eth/chain/">chain</a></li> <li> <a href="/specs/codecs/dag-eth/convenience_types/">convenience_types</a></li> <li> <a href="/specs/codecs/dag-eth/state/">state</a></li></ul></li> <li> <a href="/specs/codecs/dag-jose/">DAG-JOSE</a><ul> <li> <a href="/specs/codecs/dag-jose/fixtures/">fixtures</a></li> <li class="active-page"> <a href="/specs/codecs/dag-jose/spec/">Spec</a></li></ul></li> <li> <a href="/specs/codecs/dag-json/">DAG-JSON</a><ul> <li> <a href="/specs/codecs/dag-json/fixtures/">DAG-JSON Test Fixtures</a><ul> <li> <a href="/specs/codecs/dag-json/fixtures/cross-codec/">cross-codec</a></li></ul></li> <li> <a href="/specs/codecs/dag-json/spec/">Spec</a></li></ul></li> <li> <a href="/specs/codecs/dag-pb/">DAG-PB</a><ul> <li> <a href="/specs/codecs/dag-pb/fixtures/">DAG-PB Test Fixtures</a><ul> <li> <a href="/specs/codecs/dag-pb/fixtures/cross-codec/">cross-codec</a></li></ul></li> <li> <a href="/specs/codecs/dag-pb/spec/">Spec</a></li></ul></li></ul></li> <li> <a href="/specs/advanced-data-layouts/">Advanced Data Layouts</a><ul> <li> <a href="/specs/advanced-data-layouts/fbl/">FBL ADL</a><ul> <li> <a href="/specs/advanced-data-layouts/fbl/spec/">spec</a></li></ul></li> <li> <a href="/specs/advanced-data-layouts/hamt/">HAMT ADL</a><ul> <li> <a href="/specs/advanced-data-layouts/hamt/fixture/">HashMap (HAMT) Test Fixtures</a><ul> <li> <a href="/specs/advanced-data-layouts/hamt/fixture/alice-words/">alice-words</a></li></ul></li> <li> <a href="/specs/advanced-data-layouts/hamt/spec/">spec</a></li></ul></li></ul></li> <li> <a href="/specs/schemas/">Schemas</a><ul> <li> <a href="/specs/schemas/prelude/">prelude</a></li></ul></li> <li> <a href="/specs/transport/">Transports</a><ul> <li> <a href="/specs/transport/car/">CAR</a><ul> <li> <a href="/specs/transport/car/carv1/">CARv1 Specification</a></li> <li> <a href="/specs/transport/car/carv2/">CARv2 Specification</a></li> <li> <a href="/specs/transport/car/fixture/">CAR Test Fixtures</a><ul> <li> <a href="/specs/transport/car/fixture/carv1-basic/">carv1-basic</a></li> <li> <a href="/specs/transport/car/fixture/carv2-basic/">carv2-basic</a></li></ul></li></ul></li> <li> <a href="/specs/transport/graphsync/">Graphsync</a><ul> <li> <a href="/specs/transport/graphsync/known_extensions/">known_extensions</a></li></ul></li> <li> <a href="/specs/transport/trustless-pathing/">Trustless Pathing</a><ul> <li> <a href="/specs/transport/trustless-pathing/fixtures/">Trustless Pathing Fixtures</a><ul> <li> <a href="/specs/transport/trustless-pathing/fixtures/unixfs_20m_variety/">unixfs_20m_variety</a></li></ul></li></ul></li></ul></li> <li> <a href="/specs/selectors/">Selectors</a><ul> <li> <a href="/specs/selectors/fixtures/">fixtures</a><ul> <li> <a href="/specs/selectors/fixtures/selector-fixtures-1/">selector-fixtures-1</a></li> <li> <a href="/specs/selectors/fixtures/selector-fixtures-adl/">selector-fixtures-adl</a></li> <li> <a href="/specs/selectors/fixtures/selector-fixtures-recursion/">selector-fixtures-recursion</a></li></ul></li></ul></li> <li> <a href="/specs/patch/">Patch</a><ul> <li> <a href="/specs/patch/fixtures/">IPLD Patch Test Fixtures</a><ul> <li> <a href="/specs/patch/fixtures/fixtures-1/">fixtures-1</a></li></ul></li></ul></li></ul></li> <li> <a href="/libraries/">Libraries</a><ul> <li> <a href="/libraries/golang/">Golang</a></li> <li> <a href="/libraries/javascript/">JavaScript</a></li> <li> <a href="/libraries/python/">Python</a></li> <li> <a href="/libraries/rust/">Rust</a></li></ul></li> <li> <a href="/design/">Design</a><ul> <li> <a href="/design/objectives/">Objectives</a></li> <li> <a href="/design/concepts/">Concepts</a><ul> <li> <a href="/design/concepts/type-theory-glossary/">type-theory-glossary</a></li></ul></li> <li> <a href="/design/libraries/">Libraries</a><ul> <li> <a href="/design/libraries/nodes-and-kinds/">nodes-and-kinds</a></li></ul></li> <li> <a href="/design/tricky-choices/">Tricky Choices</a><ul> <li> <a href="/design/tricky-choices/dag-pb-forms-impl-and-use/">dag-pb-forms-impl-and-use</a></li> <li> <a href="/design/tricky-choices/map-key-domain/">map-key-domain</a></li> <li> <a href="/design/tricky-choices/numeric-domain/">numeric-domain</a></li> <li> <a href="/design/tricky-choices/ordering/">ordering</a></li> <li> <a href="/design/tricky-choices/string-domain/">string-domain</a></li></ul></li> <li> <a href="/design/open-research/">Open Research</a><ul> <li> <a href="/design/open-research/ADL-autoexecution/">ADL autoexecution</a></li></ul></li></ul></li> <li> <a href="/tools/">Tools</a></li> <li> <a href="/glossary/">Glossary</a></li> <li> <a href="/media/">Media</a></li> <li> <a href="/FAQ/">FAQ</a></li></ul> </nav> </aside> <main> <div class=content> <h1>Specification: DAG-JOSE</h1> <p><strong>Status: Descriptive - Draft</strong></p> <p>JOSE is a standard for signing and encrypting JSON objects. The various specifications for JOSE can be found in the <a href="https://datatracker.ietf.org/wg/jose/documents/">IETF datatracker</a>.</p> <h2 id="format" tabindex="-1"><a class="header-anchor" href="#format">Format</a></h2> <p>The are two kinds of JOSE objects: JWS (<a href="https://datatracker.ietf.org/doc/rfc7515/?include_text=1">JSON web signature</a>) and JWE (<a href="https://datatracker.ietf.org/doc/rfc7516/?include_text=1">JSON web encryption</a>). These two objects are primitives in JOSE and can be used to create JWT and JWM objects etc. The IETF RFCs specify a JSON encoding of JOSE objects. This specification maps the JSON encoding to CBOR. Upon encountering the <code>dag-jose</code> multiformat implementations can be sure that the block contains dag-cbor encoded data which matches the IPLD schema we specify below.</p> <h3 id="mapping-from-the-jose-general-json-serialization-to-dag-jose-serialization" tabindex="-1"><a class="header-anchor" href="#mapping-from-the-jose-general-json-serialization-to-dag-jose-serialization">Mapping from the JOSE general JSON serialization to dag-jose serialization</a></h3> <p>Both JWS and JWE supports three different serialization formats: <code>Compact Serialization</code>, <code>Flattened JSON Serialization</code>, and <code>General JSON Serialization</code>. The first two are more concise, but they only allow for one recipient. Therefore DAG JOSE always uses the <code>General Serialization</code> which ensures maximum compatibility with minimum ambiguity. Libraries implementing serialization should accept all JOSE formats including the <code>Decoded Representation</code> (see below) and convert them if necessary.</p> <p>To map the general JSON serialization to CBOR we do the following:</p> <ul> <li>Any field which is represented as <code>base64url(<data>)</code> we map directly to <code>Bytes</code> . For fields like <code>header</code> and <code>protected</code> which are specified as the <code>base64url(ascii(<some json>))</code> that means that the value is the <code>ascii(<some json>)</code> bytes.</li> <li>For JWS we specify that the <code>payload</code> property MAY be a CID, and we set the <code>payload</code> of the encoded JOSE object to <code>Bytes</code> containing the bytes of the CID. For applications where an additional network request to retrieve the linked content is undesirable then an <code>identity</code> multihash should be used.</li> <li>Besides a CID the JWS <code>payload</code> can also be arbitrary JSON. We also support including CIDs inside of this json data. However, as opposed to <em>dag-json</em> we use strings containing an IPFS uri <code>ipfs://<cid></code>, instead of an object <code>{ "/": "<cid>" }</code> which is what <code>dag-json</code> does.</li> <li>For JWE objects the <code>ciphertext</code> must decrypt to a cleartext which is the bytes of a CID. The same approach of using an <code>identity</code> multihash can be used, and most likely will be the only way to retain the confidentiality of data.</li> </ul> <p>Below we present an IPLD schema representing the encoded JOSE objects. Note that there are two IPLD schemas, <code>EncodedJWE</code> and <code>EncodedJWS</code>. The actual wire format is a single struct which contains all the keys from both the <code>EncodedJWE</code> and the <code>EncodedJWS</code> structs, implementors should follow <a href="https://tools.ietf.org/html/rfc7516#section-9">section 9 of the JWE spec</a> and distinguish between these two branches by checking if the <code>payload</code> attribute exists, and hence you have a JWS; or the <code>ciphertext</code> attribute, hence you have a JWE.</p> <p><strong>Encoded JOSE</strong></p> <pre class="language-ipldsch"><code class="language-ipldsch"><span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">EncodedSignature</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> header <span class="token keyword">optional</span> <span class="token punctuation">{</span>String<span class="token punctuation">:</span>Any<span class="token punctuation">}</span> protected <span class="token keyword">optional</span> Bytes signature Bytes <span class="token punctuation">}</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">EncodedRecipient</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> encrypted_key <span class="token keyword">optional</span> Bytes header <span class="token keyword">optional</span> <span class="token punctuation">{</span>String<span class="token punctuation">:</span>Any<span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">EncodedJWE</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> aad <span class="token keyword">optional</span> Bytes ciphertext Bytes iv <span class="token keyword">optional</span> Bytes protected <span class="token keyword">optional</span> Bytes recipients <span class="token punctuation">[</span>EncodedRecipient<span class="token punctuation">]</span> tag <span class="token keyword">optional</span> Bytes unprotected <span class="token keyword">optional</span> <span class="token punctuation">{</span>String<span class="token punctuation">:</span>Any<span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">EncodedJWS</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> payload <span class="token keyword">optional</span> Bytes signatures <span class="token punctuation">[</span>EncodedSignature<span class="token punctuation">]</span> <span class="token punctuation">}</span></code></pre> <h2 id="padding-for-encryption" tabindex="-1"><a class="header-anchor" href="#padding-for-encryption">Padding for encryption</a></h2> <p>Applications may need to pad the cleartext when encrypting to avoid leaking the size of the cleartext. This raises the question of how the application knows what part of the decrypted cleartext is padding. In this case we use the fact that the cleartext MUST be a valid CID, implementations should parse the cleartext as a CID and discard any content beyond the multihash digest size - which we assume to be the padding.</p> <h2 id="decoded-jose" tabindex="-1"><a class="header-anchor" href="#decoded-jose">Decoded JOSE</a></h2> <p>Typically implementations will want to decode this format into something more useful for applications. Exactly what that will look like depends on the language of the implementation, here we use the IPLD schema language to give a somewhat language agnostic description of what the decoded representation might look like at runtime. Note that everything which is specified as <code>base64url(ascii(<some JSON>))</code> in the JOSE specs - and which we encode as <code>Bytes</code> in the wire format - is here decoded to a <code>String</code>. We also add the <code>link &Any</code> attribute to the <code>DecodedJWS</code> if the payload is a CID, so that applications to easily retrieve the authenticated content. Otherwise, if the content of the <code>payload</code> is not a CID, it MUST be JSON. While decoding the json data from the payload, all strings must be checked if they match the regex <code>/ipfs:\/\/[a-zA-Z0-9]+$/</code>. If so they should be converted to a <code>Link</code> type. Note that we don't support dag-json like types. Finally the decoded payload should be added to the <code>pld</code> field, while the <code>payload</code> retains the base64url encoded data.</p> <p>Also note that, as with the encoded representation, there are two different representations; <code>DecodedJWE</code> and <code>DecodedJWS</code>. Applications can distinguish between these two branches in the same way as with the Encoded representation described above.</p> <pre class="language-ipldsch"><code class="language-ipldsch"><span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">DecodedSignature</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> header <span class="token keyword">optional</span> <span class="token punctuation">{</span>String<span class="token punctuation">:</span>Any<span class="token punctuation">}</span> protected <span class="token keyword">optional</span> String signature String <span class="token punctuation">}</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">DecodedJWS</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> payload String signatures <span class="token punctuation">[</span>DecodedSignature<span class="token punctuation">]</span> link <span class="token keyword">optional</span> <span class="token punctuation">&</span>Any pld <span class="token keyword">optional</span> <span class="token punctuation">{</span>String<span class="token punctuation">:</span>Any<span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">DecodedRecipient</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> encrypted_key <span class="token keyword">optional</span> String header <span class="token keyword">optional</span> <span class="token punctuation">{</span>String<span class="token punctuation">:</span>Any<span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token typedef"><span class="token keyword">type</span> <span class="token class-name">DecodedJWE</span></span> <span class="token builtin">struct</span> <span class="token punctuation">{</span> aad <span class="token keyword">optional</span> String ciphertext String iv String protected String recipients <span class="token punctuation">[</span>DecodedRecipient<span class="token punctuation">]</span> tag String unprotected <span class="token keyword">optional</span> <span class="token punctuation">{</span>String<span class="token punctuation">:</span>Any<span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre> <h2 id="implementations" tabindex="-1"><a class="header-anchor" href="#implementations">Implementations</a></h2> <ul> <li><a href="https://github.com/oed/js-dag-jose">Javascript</a></li> <li><a href="https://github.com/alexjg/go-dag-jose">Go</a></li> <li><a href="https://github.com/ceramicnetwork/rust-dag-jose">Rust</a></li> </ul> </div> </main> </body> </html>