Method GET/.well-known/did.json

Serve the decentralized identity document of a brand on its own domain name, in delegated mode. Public endpoint, resolved from the host name called.

On this page

You retrieve the decentralized identity document of a brand, published under the domain name of that brand. This document lists the public keys with which the brand signs its digital product passports. By the end of this page, you will know how to call this address, read every field of the document, and tell apart a domain that is not yet recognized from a recognized domain for which no brand has been declared.

Full address, with an example domain:

HTTP
GET https://id.exemple-sas.example/.well-known/did.json

This endpoint does not read like the others. The path is always the same for everyone. It is the host name called that designates the brand. The server reads the Host header of your request, looks for the brand that declared this domain name in delegated mode, and serves the document of that brand.

The same endpoint also answers under the /v1 prefix, at https://id.exemple-sas.example/v1/.well-known/did.json. Both addresses call the same code. No did:web resolver uses this second form: the specification requires the path /.well-known/did.json at the root of the domain. Call the form without a prefix.

#Authorization

None, this is a public endpoint. You send no API key, no session, and no origin header. The response is the same for everyone. That is what allows a third party verifier to check the signature of a passport with a standard did:web library, without an account with us.

#Rate limit

No limit of its own for this endpoint. This path falls under the general counter of the API, counted per calling network address over a slice of 60 seconds.

This fallback counter is shared by every path that has no limit of its own. The calls you make to one of them therefore eat into the budget of the others. The /v1 prefix does not create a second budget.

Every response carries the headers X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Read X-RateLimit-Remaining to know how many calls you have left in the current window. X-RateLimit-Reset carries the moment of the switch to the next window, in seconds since January 1, 1970.

Plan for the 429 code in your client and respect the Retry-After header it carries. The value of the general counter can change without notice: set your pace on the headers of your responses, and hard code no number in your code.

#Path and query parameters

This endpoint has no path parameter and no query parameter. The path is fixed and identical for every brand.

#Headers

NameTypeRequiredDescription
HoststringyesThe host name that designates the brand. It is the only element of the request that the server reads to choose the response. Your HTTP client fills it in automatically from the address you call.

The server folds this host name to lowercase and strips the port number from it before looking for the brand. ID.Exemple-SAS.example and id.exemple-sas.example:443 therefore designate the same brand.

No other header is required.

#Request body

None. This request has no body.

#Example request

Identity document of the fictional brand Exemple SAS, published on its delegated domain id.exemple-sas.example.

curl -i https://id.exemple-sas.example/.well-known/did.json

#Example response

HTTP code 200. A brand that has rotated its key once publishes two verification methods, the old one and the new one.

JSON
{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/jws-2020/v1"
  ],
  "id": "did:web:id.exemple-sas.example",
  "verificationMethod": [
    {
      "id": "did:web:id.exemple-sas.example#key-1",
      "type": "JsonWebKey2020",
      "controller": "did:web:id.exemple-sas.example",
      "publicKeyJwk": {
        "kty": "EC",
        "crv": "P-256",
        "x": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
        "y": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
      }
    },
    {
      "id": "did:web:id.exemple-sas.example#key-2",
      "type": "JsonWebKey2020",
      "controller": "did:web:id.exemple-sas.example",
      "publicKeyJwk": {
        "kty": "EC",
        "crv": "P-256",
        "x": "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC",
        "y": "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
      }
    }
  ],
  "assertionMethod": [
    "did:web:id.exemple-sas.example#key-1",
    "did:web:id.exemple-sas.example#key-2"
  ],
  "authentication": [
    "did:web:id.exemple-sas.example#key-1",
    "did:web:id.exemple-sas.example#key-2"
  ]
}

The response has five fields and nothing else.

FieldTypeDescription
@contextstring[]The two vocabularies that give their meaning to the other fields. Always https://www.w3.org/ns/did/v1 then https://w3id.org/security/suites/jws-2020/v1, in that order.
idstringThe decentralized identifier of the brand, of the form did:web: followed by the domain name called. It is the value carried by the issuer field of the passports signed by this brand.
verificationMethodobject[]The list of the public keys of the brand. One entry per key. See the table below.
assertionMethodstring[]The identifiers of the keys allowed to sign a passport, in the same order as verificationMethod.
authenticationstring[]The same list of identifiers as assertionMethod.

Each entry of verificationMethod carries four fields.

FieldTypeDescription
idstringThe identifier of the key, of the form <identifier of the brand>#key-<version number>. It is the value carried by the kid header of a signed passport, and it is what tells you which key to use.
typestringAlways JsonWebKey2020.
controllerstringThe decentralized identifier of the brand. Same value as the id field of the document.
publicKeyJwkobjectThe public key in JSON Web Key format. A key on the NIST P-256 elliptic curve: kty reads EC, crv reads P-256, x and y are the two coordinates of the public point, encoded in base64url.

The response also carries these headers.

HeaderContent
Content-Typeapplication/json.
Cache-Controlno-store, max-age=0. The response must be kept in no intermediate cache.
X-Request-IdThe identifier of your call on our side. Give this value to support when you report an unexpected response.
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-ResetYour budget of calls, see the Rate limit section.

#What the list of keys contains

The keys are returned from the oldest version to the most recent, by ascending version number.

A key taken out of service stays in the document as long as it has not been revoked. That is intended: a passport signed under an older version keeps verifying after a rotation. Take the key whose identifier matches the kid header of the passport you are verifying, never the last one of the list.

A revoked key disappears from the document. The signatures produced with it then stop verifying, and that is the expected result.

A brand that has no key yet receives a valid document whose verificationMethod, assertionMethod and authentication are empty lists. Plan for this case in your code.

#Pointing your domain

Three ways of hosting the document exist, and only one goes through this address on our side.

ModeWhere the document livesResolved address
Platformon our side, under our domain namehttps://api.sealtrust.io/brand/{brand_id}/did.json
Self-hostedon your side, you serve the file yourselfhttps://your-domain/.well-known/did.json
Delegatedon our side, under your domain namehttps://your-domain/.well-known/did.json

Platform mode is the one applied by default. Delegated mode is the one this page describes. The mode applied to your brand is set by SealTrust. Write to contact@sealtrust.io to change it.

#Errors

The body of an error response carries a detail field, except for the 400 described below. Every response carries an X-Request-Id header, the identifier of your call on our side.

CodeConditionWhat to do
400The domain name called is not declared with us. The response is plain text, Invalid host header, with no detail field. A request with no Host header, or with an empty Host header, receives the same 400.Contact support to have your delegated domain declared before putting the identity into service.
404No brand has declared this domain name as its identity domain in delegated mode. detail reads No DID Document for this host.Check the domain name called. A brand in platform mode or in self-hosted mode never answers here, even if its domain points to us.
422The identity document of the brand found cannot be built. detail carries the reason for the refusal.Report it to support, indicating the domain name called. There is nothing you can fix on your side.
429Too many calls from your network address. The response carries the Retry-After header, in seconds.Wait the number of seconds given by Retry-After, then retry. Space out your calls: the counter is shared with all the other paths that have no limit of their own.
500An unexpected error occurred while processing your call. detail reads Internal Server Error.Retry. If the error persists, contact support with the value of X-Request-Id.

#See also

Your answer opens a pre-filled email in your mail app, addressed to contact@sealtrust.io. You read it over before sending it.

Suggest a correctionReport a problem