Implementation

@discoxyz/selective-disclosure (early alpha)

Early Alpha Release of Disco Selective Disclosure SDK, provide us feedback ask@disco.xyz!

Prerequisite

Some knowledge of React.

Some knowledge of working with wallets such as Metamask or Rainbow.

A Disco developer API key.

Installation

To get started, add @discoxyz/selective-disclosure to your project:

yarn add @discoxyz/selective-disclosure

Key exports

DisclosureProvider

This provider handles API keys and authentication, to trigger the modal and access storage resources. For example, use this approach in the index.tsx file of the React project.

import { DisclosureProvider } from '@discoxyz/selective-disclosure'

// Currently we support disco & ceramic endpoints
const config = {
        projectKey: 'ABCD...' // Your Disco API key
}

const App = ({children}) => {
    return (
        <DisclosureProvider config={config}>
            {children}
        </DisclosureProvider>
    )
}

requestAsync(request, provider)

request

An object representing the credential, or collection of credentials, that you are looking for.

const requestShape = {
        'AND': [ // This means that each criteria must be met
            {
                schema: [Membership], // Will find a match from an array
                issuer: [Disco]
            },{
                schema: [Participation],
                issuer: [Guild]
            }
        ]
    }

Response

{
    status: 'success',
    message: 'Presented 2 credentials successfully',
    presentation: ...
}

Requesting a Presentation Example

import { useDiscoDisclosure } from "@discoxyz/selective-disclosure";
import ( React } from "react";
import { useAccount } from "wagmi";

const Disclose: React.FC = () => {
    
    // ✅ Use Request Async
    const { requestAsync } = useDiscoDisclosure();
    
    // Store the result
    const [result, setResult] = useState<RequestResult | undefined>()
    
    const requestShape = {
        sdRequest: {
            'AND': [ // This means that each criteria must be met
                {
                    schema: ["Membership"], // required
                    issuer: [<DiscoDID>], // optional
                    count: 1 // optional and defaults to 1 
                },{
                    schema: ["Participation"], // required
                    issuer: [<GuildDID>], // optional
                    count: 2 // optional and defaults to 1 
                }
            ]
        }
    }
    
    async function sendRequest() {
        
        // 📨 Send the request. This triggers a modal for the user
        const result = await requestAsync(requestShape)
        
        // If no presentation, errors are present
        if (!result.presentation) return
        
        // Now set the result
       setResult(result)
    }


    return (
        <div>
            <button onClick={sendRequest}>Reveal Credential</button>
            {result ? <p>{status.message}</p>
            : <p>Request not started</p>}
        </div>
    )
}

Example of a Verifiable Presentation from const result = await requestAsync(provider, requestShape)from above code snippet.

{
  "presentation": {
    "@context": [
      "https://www.w3.org/2018/credentials/v1"
    ],
    "type": [
      "VerifiablePresentation"
    ],
    "issuanceDate": "2023-11-17T18:10:51.945Z",
    "verifiableCredential": [
      "{\"@context\":[\"https://www.w3.org/2018/credentials/v1\"],\"type\":[\"VerifiableCredential\",\"GmCredential\"],\"issuer\":{\"id\":\"did:web:staging-be.disco.xyz/v1/mick\"},\"issuanceDate\":\"2023-09-22T14:53:58.452Z\",\"id\":\"https://api.disco.xyz/credential/7170505e-37b1-49bb-8cd0-bd4709b4e9db\",\"credentialSubject\":{\"id\":\"did:3:kjzl6cwe1jw149lyliyfh4mbjgy59rhoktkhsoc7suu2trqje2wigrgea21bqy6\"},\"credentialSchema\":{\"id\":\"https://raw.githubusercontent.com/discoxyz/disco-schemas/main/json/GMCredential/1-0-0.json\",\"type\":\"JsonSchemaValidator2018\"}}",
      "{\"@context\":[\"https://www.w3.org/2018/credentials/v1\"],\"type\":[\"VerifiableCredential\",\"GmCredential\"],\"issuer\":{\"id\":\"did:3:kjzl6cwe1jw14a7u9sx3thx9gg9uh7u5tqjkzcnr5pi5zzkap7kiztgsfhzayzt\"},\"issuanceDate\":\"2023-09-22T12:00:17.369Z\",\"id\":\"https://api.disco.xyz/credential/098514a6-1e3c-4209-8507-212dbed37169\",\"credentialSubject\":{\"id\":\"did:3:kjzl6cwe1jw149lyliyfh4mbjgy59rhoktkhsoc7suu2trqje2wigrgea21bqy6\"},\"credentialSchema\":{\"id\":\"https://raw.githubusercontent.com/discoxyz/disco-schemas/main/json/GMCredential/1-0-0.json\",\"type\":\"JsonSchemaValidator2018\"},\"proof\":{\"verificationMethod\":\"did:3:kjzl6cwe1jw14a7u9sx3thx9gg9uh7u5tqjkzcnr5pi5zzkap7kiztgsfhzayzt#controller\",\"created\":\"2023-09-22T12:00:17.390Z\",\"proofPurpose\":\"assertionMethod\",\"type\":\"EthereumEip712Signature2021\",\"proofValue\":\"0x100353098f280cd351f3b9ee22642854f4b38ac99ef6ab13d874b26afdff44886101130b1270c2031a657774446e2cbbaf25ab32178959a3fe167365810d00801c\",\"eip712Domain\":{\"domain\":{\"chainId\":1,\"name\":\"Disco Verifiable Credential\",\"version\":\"1\"},\"messageSchema\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"}],\"Proof\":[{\"name\":\"created\",\"type\":\"string\"},{\"name\":\"proofPurpose\",\"type\":\"string\"},{\"name\":\"type\",\"type\":\"string\"},{\"name\":\"verificationMethod\",\"type\":\"string\"}],\"Issuer\":[{\"name\":\"id\",\"type\":\"string\"}],\"CredentialSubject\":[{\"name\":\"id\",\"type\":\"string\"}],\"VerifiableCredential\":[{\"name\":\"@context\",\"type\":\"string[]\"},{\"name\":\"credentialSubject\",\"type\":\"CredentialSubject\"},{\"name\":\"id\",\"type\":\"string\"},{\"name\":\"issuanceDate\",\"type\":\"string\"},{\"name\":\"issuer\",\"type\":\"Issuer\"},{\"name\":\"proof\",\"type\":\"Proof\"},{\"name\":\"type\",\"type\":\"string[]\"}]},\"primaryType\":\"VerifiableCredential\"}}}",
      "{\"@context\":[\"https://www.w3.org/2018/credentials/v1\"],\"type\":[\"VerifiableCredential\",\"GmCredential\"],\"issuer\":{\"id\":\"did:3:kjzl6cwe1jw14a7u9sx3thx9gg9uh7u5tqjkzcnr5pi5zzkap7kiztgsfhzayzt\"},\"issuanceDate\":\"2023-09-22T11:59:24.784Z\",\"id\":\"https://api.disco.xyz/credential/21df13f1-14d6-40a5-a27a-18a96e0980b2\",\"credentialSubject\":{\"id\":\"did:3:kjzl6cwe1jw149lyliyfh4mbjgy59rhoktkhsoc7suu2trqje2wigrgea21bqy6\"},\"credentialSchema\":{\"id\":\"https://raw.githubusercontent.com/discoxyz/disco-schemas/main/json/GMCredential/1-0-0.json\",\"type\":\"JsonSchemaValidator2018\"},\"proof\":{\"verificationMethod\":\"did:3:kjzl6cwe1jw14a7u9sx3thx9gg9uh7u5tqjkzcnr5pi5zzkap7kiztgsfhzayzt#controller\",\"created\":\"2023-09-22T11:59:24.880Z\",\"proofPurpose\":\"assertionMethod\",\"type\":\"EthereumEip712Signature2021\",\"proofValue\":\"0x9123cda1825121738eeb14c04407fd7f160deadcbac52f517f9364c92ff7dfe84fd8d26596abb781926985e499e120c0342f96c47671a80a5e2d10c189e3cd121c\",\"eip712Domain\":{\"domain\":{\"chainId\":1,\"name\":\"Disco Verifiable Credential\",\"version\":\"1\"},\"messageSchema\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"}],\"Proof\":[{\"name\":\"created\",\"type\":\"string\"},{\"name\":\"proofPurpose\",\"type\":\"string\"},{\"name\":\"type\",\"type\":\"string\"},{\"name\":\"verificationMethod\",\"type\":\"string\"}],\"Issuer\":[{\"name\":\"id\",\"type\":\"string\"}],\"CredentialSubject\":[{\"name\":\"id\",\"type\":\"string\"}],\"VerifiableCredential\":[{\"name\":\"@context\",\"type\":\"string[]\"},{\"name\":\"credentialSubject\",\"type\":\"CredentialSubject\"},{\"name\":\"id\",\"type\":\"string\"},{\"name\":\"issuanceDate\",\"type\":\"string\"},{\"name\":\"issuer\",\"type\":\"Issuer\"},{\"name\":\"proof\",\"type\":\"Proof\"},{\"name\":\"type\",\"type\":\"string[]\"}]},\"primaryType\":\"VerifiableCredential\"}}}"
    ],
    "proof": {
      "verificationMethod": "did:3:kjzl6cwe1jw149lyliyfh4mbjgy59rhoktkhsoc7suu2trqje2wigrgea21bqy6#controller",
      "created": "2023-11-17T18:10:51.945Z",
      "proofPurpose": "assertionMethod",
      "type": "EthereumEip712Signature2021",
      "proofValue": "0x1bf34c9227e7948ca8ab19589a813cb9cfc3f276aeaa14565b663f11e87719d8040c2c3cf915625412032e17b7c2441e838056e8ef5a385dc1c59702612533981c",
      "eip712": {
        "domain": {
          "chainId": 1,
          "name": "VerifiablePresentation",
          "version": "1"
        },
        "types": {
          "EIP712Domain": [
            {
              "name": "name",
              "type": "string"
            },
            {
              "name": "version",
              "type": "string"
            },
            {
              "name": "chainId",
              "type": "uint256"
            }
          ],
          "Proof": [
            {
              "name": "created",
              "type": "string"
            },
            {
              "name": "proofPurpose",
              "type": "string"
            },
            {
              "name": "type",
              "type": "string"
            },
            {
              "name": "verificationMethod",
              "type": "string"
            }
          ],
          "VerifiablePresentation": [
            {
              "name": "@context",
              "type": "string[]"
            },
            {
              "name": "issuanceDate",
              "type": "string"
            },
            {
              "name": "proof",
              "type": "Proof"
            },
            {
              "name": "type",
              "type": "string[]"
            },
            {
              "name": "verifiableCredential",
              "type": "string[]"
            }
          ]
        },
        "primaryType": "VerifiablePresentation"
      }
    }
  },
  "status": "success",
  "message": ""
}

Extracting Issuers Example

// Received Presentaion such as in sendRequest from above example
const result = {
    "presentation": {
        ..., //other properties
        "verifiableCredential": [

        ]
    },
    "status": "success",
    "message":
}

// After receiving the presentation, 
// you can extract the credentials array from the following properties.

const credentials = result.presentation.verifiableCredential

// These Credentials can either be JWT's or JSON-LD. 
// You can use a regex like below to determine 
// And a library like did-jwt or jsonwebtoken to decode the jwts.

import { decodeJWT } from "did-jwt";

const jwtRegex = /^([a-zA-Z0-9_-]+)\.([a-zA-Z0-9_-]+)\.([a-zA-Z0-9_-]+)$/;

const res = credentials.map((vc: any) => {
    return vc.match(jwtRegex) ? decodeJWT(vc).payload : JSON.parse(vc)
})

const issuers = res.map((vc:any) => {
    return vc.issuer.id;
})

//Now with the issuers we can see who signed the credential for this user
console.log(issuers)