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
npm i @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.
issuer
string[]
A list of the possible issuers of your credential
schema
string[]
An array of links to the permissible schemas. Schemas can be found at @discoxyz/schemas
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'
The user presented valid credentials
'rejected'
The user rejected the request
'invalid'
'notConnected'
The user's wallet is not connected
'invalidApi
'
The keys provided for the API are invalid.
'error'
Another error occurred. Information will be provided in the message
.
message
String
A message to help you provide context in your UI. Helpful in the case of error messages
presentation
Presentation
The Verifiable Presentation, which you can independently check to verify authenticity.
{
status: 'success',
message: 'Presented 2 credentials successfully',
presentation: ...
}
{
status: 'rejected',
message: 'The presentation request was rejected'
}
{
status: 'invalid',
message: 'The presentation was invalid'
}
{
status: 'notConnected',
message: 'No wallet is connected'
}
{
status: 'invalidApi',
message: 'An API endpoint could not be reached...'
}
{
status: 'error',
message: ...
}
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)