Skip to main content

Understanding decentralized identity (DID and DIF)

· 16 min read

What is DIF?

Decentralized Identity Foundation builds ecosystem for decentralized identity and ensures interop between all participants.

Why? … What is the problem?

ID Problem

The problem of decoupling ID from Personally identifiable information (PII). Identity is composed of a deeply personal collection of data that defines us, and your identity should answer to no one but you.

Specifically, challenges are

  1. Decoupling ID from identity providers. DIDs should be self-sovereign and not owned or controlled by central authorities.
  2. Decoupling ID lookup from centralized systems. DIDs and data should be able to be found across decentralized systems, so that no central owner can do the evil.
  3. Decoupling ID data from indiscreet or unknown storages. DIDs should be able to control precisely what to or what not to share with others.

Uniting the fragmented landscapes

DIF is the organization uniting the fragmented to solve the DID problem together and build an ecosystem as an industry standard.

How do they organize the efforts?

  • Designing Specs
  • Implementations
  • Aligning industry participants

People and Organizations

Working Groups

  • ID, Names, Discovery
  • Storage and Compute
  • Claims and Credentials

Members

  • Blockstack
  • Microsoft / IBM
  • HyperLedger
  • RSA
  • Ontology
  • Civic
  • iota

Ecosystem

DIF Ecosystem

DID

ID that is

  1. globally unique
  2. resolveable with high availability, and
  3. cryptographically verifiable.

DID Format: URN

Format in URN

DID methods (further explained below) define how DIDs work with a specific blockchain.

DID Document

  • DID infrastructure = a global key-value database of <DID, DID Document>
  • DID document = public keys, authentication protocols, and service endpoints for verifying the entity and explaining how to use it. It may contain three things:
    • proof purposes
    • verification methods
    • service endpoints

How DID preserves privacy?

  1. Pairwise-pseudonymous DIDs
  2. Off-chain private data
  3. Selective disclosure

DID method specification (DID <> Blockchain)

Defining how a DID and DID document are created, resolved, and managed (CRUD) on a specific blockchain.

How to join the DID method registration?

https://w3c-ccg.github.io/did-method-registry/#the-registry

Examples

Learning by Example: Blockstack DID method

  • How Blockstack leverages DID?
  • How to create a blockstack DID? How Blockstack acts as an Identity Provider?
  • How to resolve a DID?

Blockstack Naming Service (BNS)

  • Naming Layer = username <> pub key & pointer to storage
  • BNS is blockchain-agnostic. migrated from namecoint to bitcoin.
  • ==a Blockstack DID is defined as a pointer to the nth name registered by an address==.

two categories

on-chain DIDs

  • two tx to register a name on-chain - owner address <> name
  • one owner address may have multiple on-chain names and corresponding DIDs
    • e.g. did:stack:v0:15gxXgJyT5tM5A4Cbx99nwccynHYsBouzr-3 means the fourth on-chain name was created and initially assigned to the address 15gxXgJyT5tM5A4Cbx99nwccynHYsBouzr.

off-chain DIDs. a.k.a. subdomains

  • encoded in batches, hashed, and written to a blockchain later.

  • Off-chain names are instantiated by an on-chain name, indicated by the off-chain name's suffix. cicero.res_publica.id is processed by the owner of res_publica.id but are not owned by it.

Blockstack as an Identity Provider

Demo: https://bitpatron.co/ login with Blockstack

sequenceDiagram User ->> First Party: GET /login Note left of User: Login Note right of First Party: store transitKey First Party ->> User: Redirect User ->> Blockstack: GET /auth?authRequest=:authRequestJwt Blockstack ->> First Party: GET /manifest.json (CORS) Note left of User: create or select ID Blockstack ->> User: Redirect User ->> First Party: GET /auth?authResponse=:authResponseJwt Note right of First Party: decrypt w. transitKey Note left of First Party: pending sign-in First Party ->> Blockstack: GET /v1/names/:acctName.id.blockstack Blockstack ->> First Party: UserData

// authRequestJwt
{
"typ": "JWT",
"alg": "ES256K"
}
{
"jti": "4d06f08b-67a7-4f7c-89fc-b8164b81f67a",
"iat": 1563432343,
"exp": 1566110743,
"iss": "did:btc-addr:19sxvnAxPXZYAEdpF7Tti6MSVhxA8PSdCT",
"public_keys": [
"03994ec7b23a8e11e40684c9b2d29febf103bd92c4bbd295f1e2537042c93ac977"
],
"domain_name": "http://localhost:4104",
"manifest_uri": "http://localhost:4104/manifest.json",
"redirect_uri": "http://localhost:4104/",
"version": "1.3.1",
"do_not_include_profile": true,
"supports_hub_url": true,
"scopes": [
"store_write"
]
}
// authResponse
{
"typ": "JWT",
"alg": "ES256K"
}
{
"jti": "30773b78-3595-499f-bbb3-d1e649470c70",
"iat": 1563432894,
"exp": 1566111294,
"iss": "did:btc-addr:1DpKMqxBnuSSQMNun1obciPSfD9rD8KNUH",
"private_key": "redacted - encrypted with transitKey",
"public_keys": [
"027c8547681cc27e27b73ee0f3c0534bdd38993dcb4c1934bf424f0b3a04dcad63"
],
"profile": null,
"username": "kirbystar.id.blockstack",
"core_token": null,
"email": null,
"profile_url": "https://gaia.blockstack.org/hub/1DpKMqxBnuSSQMNun1obciPSfD9rD8KNUH/profile.json",
"hubUrl": "https://hub.blockstack.org",
"blockstackAPIUrl": "https://core.blockstack.org",
"associationToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJjaGlsZFRvQXNzb2NpYXRlIjoiMDNhMTU5YzY4YWQ1ZjFkNzcxMWY2NjJmNThkNjdmMzZlNzY3ZTBjMDBhOTU4ZWY0NzljNzU3MzU0MGFkMzExZjk2IiwiaXNzIjoiMDI3Yzg1NDc2ODFjYzI3ZTI3YjczZWUwZjNjMDUzNGJkZDM4OTkzZGNiNGMxOTM0YmY0MjRmMGIzYTA0ZGNhZDYzIiwiZXhwIjoxNTk0OTY4ODk0LjcwNSwiaWF0IjoxNTYzNDMyODk0LjcwNSwic2FsdCI6IjE4NGVhMWQyMzM3MWQ1MmYyYzhmNTAyOGUwMWYxYmZiIn0.ZceaVcIK2Z8wu6KBYOHQaK7y6BI7NfxrixphOCPs1B4hZcGYDKsuf0anbm4CdAAJbKRifCm-MYHE6fjKD9E7GQ",
"version": "1.3.1"
}
// acctName response
{
"blockchain": "bitcoin",
"status": "submitted_subdomain",
"last_txid": "851ca5e6c06723e61037aa397966aafa1a6dd7159e9e31e53116106b87101886",
"zonefile": "$ORIGIN kirbystar.id.blockstack\n$TTL 3600\n_http._tcp\tIN\tURI\t10\t1\t\"https://gaia.blockstack.org/hub/1DpKMqxBnuSSQMNun1obciPSfD9rD8KNUH/profile.json\"\n\n",
"address": "1DpKMqxBnuSSQMNun1obciPSfD9rD8KNUH",
"zonefile_hash": "a9c016921a9a60e04776251db53a8881e6d128ce"
}
// session
{
"version": "1.0.0",
"userData": {
"username": "kirbystar.id.blockstack",
"profile": {
"@type": "Person",
"@context": "http://schema.org",
"api": {
"gaiaHubConfig": {
"url_prefix": "https://gaia.blockstack.org/hub/"
},
"gaiaHubUrl": "https://hub.blockstack.org"
}
},
"email": null,
"decentralizedID": "did:btc-addr:1DpKMqxBnuSSQMNun1obciPSfD9rD8KNUH",
"identityAddress": "1DpKMqxBnuSSQMNun1obciPSfD9rD8KNUH",
"appPrivateKey": "redacted",
"coreSessionToken": null,
"authResponseToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJqdGkiOiIyNmM4ZGM2Ny1lNzEwLTRlZDUtYmIxYi0yY2I1ODY5YTRkMTEiLCJpYXQiOjE1NjM0MzU2NjEsImV4cCI6MTU2NjExNDA2MSwiaXNzIjoiZGlkOmJ0Yy1hZGRyOjFEcEtNcXhCbnVTU1FNTnVuMW9iY2lQU2ZEOXJEOEtOVUgiLCJwcml2YXRlX2tleSI6IjdiMjI2OTc2MjIzYTIyNjQzMDMzMzMzODMyNjYzNTYxNjIzNjM0Mzg2MTM1MzYzNTM2MzI2MzMzNjEzMTYyMzY2NTYzNjEzNzMzNjU2NjIyMmMyMjY1NzA2ODY1NmQ2NTcyNjE2YzUwNGIyMjNhMjIzMDMyNjEzMzY1NjEzMzY0NjMzNjMyMzgzODY2MzgzMTY2MzAzNDMwMzU2MzY1MzI2MzMzNjUzNjY0MzMzMzMxMzQzNDM0NjY2MTM4MzA2NTY1MzIzMzMyNjEzMjM2NjQzMzMwMzczMzM2MzY2NTMzMzkzNzM3MzczMjMxMzMzNzM5MzcyMjJjMjI2MzY5NzA2ODY1NzI1NDY1Nzg3NDIyM2EyMjM2MzMzOTYzNjMzMDM5MzQzOTYyMzMzNjY0NjI2NTM1MzIzMTM0MzIzMjM3MzA2MzY1NjIzMTM0MzEzNjY2MzA2MzM0NjYzNDM4MzgzMjY0MzUzOTM0MzMzNDM2NjM2NjYyNjEzNzMxNjM2MjM1MzYzMTM2MzczMDY0MzUzMzY0MzQzNTY1MzMzODYyNjIzNzM1NjMzMjMzMzYzNjMyMzUzODMxMzgzOTM3NjYzMjMwNjMzNTM4MzA2NTMyMzEzODM0MzMzNTMwMzMzNjM1NjE2NDM1NjEzMTM4NjY2MjMyNjY2NDM3MzQ2MzY1NjMzNDM0MzI2NTY0MzY2NTY2NjYzMjM5NjIzNjY2Mzk2MTMyMzgzMTM4MzEzMzYyMzMzMDYyMzkzMTYzMzE2MzM1Mzg2MTM4MzgzMTM5MzQ2MjYzMjIyYzIyNmQ2MTYzMjIzYTIyMzkzNzY0MzM2MzM4NjEzOTYxMzQ2NjMyMzkzNjM1MzM2MzM1MzQzNzY1MzIzNTYzMzMzMzM4MzIzMDYxMzczMjYyMzU2NjY0MzQ2NjM1NjE2NDYxNjY2NjMwMzQzNzM1Mzk2NDM0MzI2MTYxMzgzNDM1MzkzNzY2MzY2MjM5NjEyMjJjMjI3NzYxNzM1Mzc0NzI2OTZlNjcyMjNhNzQ3Mjc1NjU3ZCIsInB1YmxpY19rZXlzIjpbIjAyN2M4NTQ3NjgxY2MyN2UyN2I3M2VlMGYzYzA1MzRiZGQzODk5M2RjYjRjMTkzNGJmNDI0ZjBiM2EwNGRjYWQ2MyJdLCJwcm9maWxlIjpudWxsLCJ1c2VybmFtZSI6ImtpcmJ5c3Rhci5pZC5ibG9ja3N0YWNrIiwiY29yZV90b2tlbiI6bnVsbCwiZW1haWwiOm51bGwsInByb2ZpbGVfdXJsIjoiaHR0cHM6Ly9nYWlhLmJsb2Nrc3RhY2sub3JnL2h1Yi8xRHBLTXF4Qm51U1NRTU51bjFvYmNpUFNmRDlyRDhLTlVIL3Byb2ZpbGUuanNvbiIsImh1YlVybCI6Imh0dHBzOi8vaHViLmJsb2Nrc3RhY2sub3JnIiwiYmxvY2tzdGFja0FQSVVybCI6Imh0dHBzOi8vY29yZS5ibG9ja3N0YWNrLm9yZyIsImFzc29jaWF0aW9uVG9rZW4iOiJleUowZVhBaU9pSktWMVFpTENKaGJHY2lPaUpGVXpJMU5rc2lmUS5leUpqYUdsc1pGUnZRWE56YjJOcFlYUmxJam9pTUROaE1UVTVZelk0WVdRMVpqRmtOemN4TVdZMk5qSm1OVGhrTmpkbU16WmxOelkzWlRCak1EQmhPVFU0WldZME56bGpOelUzTXpVME1HRmtNekV4WmprMklpd2lhWE56SWpvaU1ESTNZemcxTkRjMk9ERmpZekkzWlRJM1lqY3paV1V3WmpOak1EVXpOR0prWkRNNE9Ua3paR05pTkdNeE9UTTBZbVkwTWpSbU1HSXpZVEEwWkdOaFpEWXpJaXdpWlhod0lqb3hOVGswT1RjeE5qWXhMak0yT1N3aWFXRjBJam94TlRZek5ETTFOall4TGpNMk9Td2ljMkZzZENJNklqVXhOMkZsWkdVd1ltVmpOMkpqTlRnek5qY3lOREkwT1RsaE1EVm1OVEEwSW4wLjlkY2VHX3I4OVdDSUVsTklseFNtUGxPblhiSVNsZEZDejJxOTJRMnpJSk9XXzhnTjVYT0xsZnNkREJVamlQZlU3eTNyRGFXSUxfTUJicVVnVnBFanhRIiwidmVyc2lvbiI6IjEuMy4xIn0.0Xqtw-71TJ9ybWx4Uxre0Gxkisay20xn1vqwr0WaKvVeCzwv_NO6YZnVOmGPM4cF4wex06yLYWasqQWgCi-m_g",
"hubUrl": "https://hub.blockstack.org",
"gaiaAssociationToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJjaGlsZFRvQXNzb2NpYXRlIjoiMDNhMTU5YzY4YWQ1ZjFkNzcxMWY2NjJmNThkNjdmMzZlNzY3ZTBjMDBhOTU4ZWY0NzljNzU3MzU0MGFkMzExZjk2IiwiaXNzIjoiMDI3Yzg1NDc2ODFjYzI3ZTI3YjczZWUwZjNjMDUzNGJkZDM4OTkzZGNiNGMxOTM0YmY0MjRmMGIzYTA0ZGNhZDYzIiwiZXhwIjoxNTk0OTcxNjYxLjM2OSwiaWF0IjoxNTYzNDM1NjYxLjM2OSwic2FsdCI6IjUxN2FlZGUwYmVjN2JjNTgzNjcyNDI0OTlhMDVmNTA0In0.9dceG_r89WCIElNIlxSmPlOnXbISldFCz2q92Q2zIJOW_8gN5XOLlfsdDBUjiPfU7y3rDaWIL_MBbqUgVpEjxQ"
},
"transitKey": "redacted"
}

Getting Entity from DID - Universal Resolver

Domain Name <--DNS-->  IP
Repensented Entity <--Universal Resolver--> Self-sovereign Identifiers
DID <--Universal Resolver--> DID Document

Universal Resolver

Drivers for Example:

  • did:stack: DID registered from BlockStack, like did:stack:v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0
  • did:btcr: DID registered from BTC
  • etc.

Run a resolver

git clone https://github.com/decentralized-identity/universal-resolver.git
cd universal-resolver/
docker-compose -f docker-compose.yml pull
docker-compose -f docker-compose.yml up
curl -X GET http://localhost:8080/1.0/identifiers/did:stack:v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0 | jq .

{
"redirect": null,
"didDocument": {
"id": "did:stack:v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0",
"service": [
{
"type": "blockstack",
"serviceEndpoint": "https://core.blockstack.org"
}
],
"publicKey": [
{
"id": "did:stack:v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0",
"type": "Secp256k1VerificationKey2018",
"publicKeyHex": "0232131c807c4b184582280bca141f2583f6a1de2e0d3e6984cdb4724527f581fa"
}
],
"@context": "https://w3id.org/did/v0.11"
},
"resolverMetadata": {
"duration": 96,
"driverId": "did-stack",
"driver": "HttpDriver",
"didUrl": {
"didUrlString": "did:stack:v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0",
"did": {
"didString": "did:stack:v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0",
"method": "stack",
"methodSpecificId": "v0:SZBrgLTLXZL9ZAX8GVNgvZKcU4DJBXkUQr-0",
"parseTree": null,
"parseRuleCount": null
},
"parameters": null,
"parametersMap": {},
"path": "",
"query": null,
"fragment": null,
"parseTree": null,
"parseRuleCount": null
}
},
"methodMetadata": {}
}

Or use Blockstack's resolver

https://github.com/blockstack/blockstack-core/blob/master/docs/blockstack-did-spec.md#33--resolving-a-blockstack-did

DID <> Real-world: Verifiable Claims

Now we know how to recognize and resolve "who's who" without inherently carrying personally-identifiable information. However, what if we want DID to associate with real-world entities?

Imagine that Alice has a state-issued DID and wants to buy some alcohol without disclosing her real name and precise age.

drinking

The answer is to use “verifiable claims” (aka: credentials, attestations).

  1. claim = properties we know about the entity in subject-property-value relationships, e.g. name, email, age, membership, etc.
  2. verifiable = proofs (signatures) attached

Verifiable Claims Data Model

Identity Profile

type: unordered set of URIs

signature: Signature [0..1]

Entity Credential

id: URI

type: unordered set of URIs

issuer: URI

issued: date in string form

claim: Claim

Claim

(at least one custom property)

Verifiable Claim

signature: Signature

Signature

(varies, but expected to include

at least a signature, a reference

to the signing entity, and a

representation of the signing date)

id

id

1

0..*

A simple identity profile

{
"id": "did:ebfeb1f712ebc6f1c276e12ec21",
"type": ["Identity", "Person"],
"name": "Alice Bobman",
"email": "[email protected]",
"birthDate": "1985-12-14",
"telephone": "12345678910"
}

A simple claim

{
"id": "http://example.gov/credentials/3732",
"type": ["Credential", "ProofOfAgeCredential"],
"issuer": "https://dmv.example.gov",
"issued": "2010-01-01",
"claim": {
"id": "did:ebfeb1f712ebc6f1c276e12ec21",
"ageOver": 21
}
}

A simple verifiable claim

{
"@context": "https://w3id.org/security/v1",
"id": "http://example.gov/credentials/3732",
"type": ["Credential", "ProofOfAgeCredential"],
"issuer": "https://dmv.example.gov",
"issued": "2010-01-01",
"claim": {
"id": "did:ebfeb1f712ebc6f1c276e12ec21",
"ageOver": 21
},
"revocation": {
"id": "http://example.gov/revocations/738",
"type": "SimpleRevocationList2017"
},
"signature": {
"type": "LinkedDataSignature2015",
"created": "2016-06-18T21:19:10Z",
"creator": "https://example.com/jdoe/keys/1",
"domain": "json-ld.org",
"nonce": "598c63d6",
"signatureValue": "BavEll0/I1zpYw8XNi1bgVg/sCneO4Jugez8RwDg/+
MCRVpjOboDoe4SxxKjkCOvKiCHGDvc4krqi6Z1n0UfqzxGfmatCuFibcC1wps
PRdW+gGsutPTLzvueMWmFhwYmfIFpbBu95t501+rSLHIEuujM/+PXr9Cky6Ed
+W3JT24="
}
}

It equals to a JOSE JWT verifiable claim

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2Rtdi
5leGFtcGxlLmdvdiIsImlhdCI6MTI2MjMwNDAwMCwiZXhwIjoxNDgzMjI4ODAwL
CJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJkaWQ6ZWJmZWIxZjcxMmVi
YzZmMWMyNzZlMTJlYzIxIiwiZW50aXR5Q3JlZGVudGlhbCI6eyJAY29udGV4dCI
6Imh0dHBzOi8vdzNpZC5vcmcvc2VjdXJpdHkvdjEiLCJpZCI6Imh0dHA6Ly9leG
FtcGxlLmdvdi9jcmVkZW50aWFscy8zNzMyIiwidHlwZSI6WyJDcmVkZW50aWFsI
iwiUHJvb2ZPZkFnZUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiaHR0cHM6Ly9kbXYu
ZXhhbXBsZS5nb3YiLCJpc3N1ZWQiOiIyMDEwLTAxLTAxIiwiY2xhaW0iOnsiaWQ
iOiJkaWQ6ZWJmZWIxZjcxMmViYzZmMWMyNzZlMTJlYzIxIiwiYWdlT3ZlciI6Mj
F9fX0.LwqH58NasGPeqtTxT632YznKDuxEeC59gMAe9uueb4pX_lDQd2_UyUcc6
NW1E3qxvYlps4hH_YzzTuXB_R1A9UHXq4zyiz2sMtZWyJkUL1FERclT2CypX5e1
fO4zVES_8uaNoinim6VtS76x_2VmOMQ_GcqXG3iaLGVJHCNlCu4

DID and IOT

slides

Takeaways

DID

  • is probably a Differentiator for identity-oriented vendors but a Neutralizer (out of MMRs, neutralizers, and differentiators features) for others.
  • preserves privacy in a large group of products, so that no central company could know all your stuff from all your accounts from various products.
  • combined with verifiable claims, it leverage crypto but still requires trust in the physical world.

What blockchain developers can do?

  • Join DIF.
  • Proposing a DID method on how to operate DIDs on their blockchain.
  • Building our own decentralized identity provider.

References

Twitter URL