Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

Tutorials for schemas and credentials #610

Merged
merged 4 commits into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions doc/howto/credential.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# How To: Create a Credential

## Background

A [Verifiable Credential (VC)](https://www.w3.org/TR/vc-data-model/) is a standard format to package a set of claims that an _issuer_ makes about a _subject_. The Verifiable Credentials Data Model, a W3C standard, introduces a number of concepts, most notable among them, the [three party model](https://www.w3.org/TR/vc-data-model/#ecosystem-overview) of **issuers**, **holders**, and **verifiers**. The model is a novel way of empowering entities to have tamper-evident representations of their data which acts as a mechanism to present the data to any third party (a verifier) without necessitating contact between the verifier and issuer. With the three party model entities are given more [control, transparency, privacy, and utility](https://www.lifewithalacrity.com/2016/04/the-path-to-self-soverereign-identity.html) for data that is rightfully theirs.

VCs are defined by a data model, which does not provide guidance on transmitting or sharing credentials between parties (protocols). The data model also does not provide guidance on _securing_ the credential (which puts the verifiable in verifiable credential). There are two prominent options here: [Data Integrity](https://w3c.github.io/vc-data-integrity/) and [JWT](https://w3c.github.io/vc-jose-cose/) both of which we have demonstrated support for. The data model has a number of required (core) properties, and multiple means of extension to meet many use cases and functional needs.
decentralgabe marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vc-jose-cose is different than JWT for VCDM v1.1

I think it's worth clarifying this. It'll make it clear that we're producing VCs represented as v1.1 style JWTs.


## VCs in the SSI Service

VCs are a core component of SSI (Self Sovereign Identity) systems and work hand-in-hand with [DIDs](did.md). In our system, DIDs are used to represent the _issuer_ as well as the _subject_ of a credential. To define which content is in a VC we make use of [JSON schemas](schema.md).

The SSI Service is transport-agnostic and does not mandate the usage of a single mechanism to deliver credentials to an intended holder. We have begun integration with both [Web5](https://github.com/TBD54566975/dwn-sdk-js#readme) and [OpenID Connect](https://openid.net/sg/openid4vc/) transportation mechanisms but leave the door open to any number of possibile options.

At present, the service supports issuing credentials using the [v1.1 data model as a JWT](https://www.w3.org/TR/vc-data-model/#json-web-token). There is support for verifying credentials that make use of select [Data Integrity cryptographic suites](https://w3c.github.io/vc-data-integrity/) though use is discouraged due to complexity and potential security risks. Support for [v2.0](https://w3c.github.io/vc-data-model/) of the data model is planned and coming soon!

Out of the box we have support for exposing two [credential statuses](status.md) using the [Verifiable Credentials Status List](https://w3c.github.io/vc-status-list-2021/) specification: suspension and revocation.

## Creating a Verifiable Credential

Creating a credential using the SSI Service currently requires four pieces of data: an `issuer` DID, a `verificationMethodId` which must be contained within the issuer's DID Document, a `subject` DID (the DID who the claims are about), and `data` which is an arbitrary JSON object for the claims that you wish to be in the credential (in the `credentialSubject` property).

There are additional optional properties that let you specify `evidence`, an `expiry`, and whether you want to make the credential `revocable` or `suspendable`. Let's keep things simple and issue our first credential which will attest to a person's first and last name.

### 1. Create an issuer DID

We need two pieces of issuer information to create the credential: their DID and a verification method identifier. To get both, let's create a `did:key` to act as the issuer, with the following `PUT` command to `/v1/dids/key`.

```bash
curl -X PUT localhost:3000/v1/dids/key -d '{"keyType": "Ed25519"}'
```

We get back a response with the `id` as `did:key:z6Mkm1TmRWRPK6n21QncUZnk1tdYkje896mYCzhMfQ67assD`. Since we're using DID key we know that there is only a single key and its' `verificationMethodId` is the DID suffix: `did:key:z6Mkm1TmRWRPK6n21QncUZnk1tdYkje896mYCzhMfQ67assD#z6Mkm1TmRWRPK6n21QncUZnk1tdYkje896mYCzhMfQ67assD`. This value could be retrieved by resolving the DID or by making a `GET` request to `/v1/dids/key/did:key:z6Mkm1TmRWRPK6n21QncUZnk1tdYkje896mYCzhMfQ67assD` as well.

### 2. Create a person schema

Because we want to include information about the subject in the credential, let's first create a schema to define the shape of the credential's data with required `firstName` and `lastName` values.
decentralgabe marked this conversation as resolved.
Show resolved Hide resolved

Once we have our schema, we'll submit it to the service with a `PUT` request to `v1/schemas` as follows:

```bash
curl -X PUT localhost:3000/v1/schemas -d '{
"name": "Person Credential",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"credentialSubject": {
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
}
},
"required": ["firstName", "lastName"]
}
}
}
}'
```

After submission we get back an identifier to refer to the schema as `aed6f4f0-5ed7-4d7a-a3df-56430e1b2a88`.

### 3. Create a credential

Separately, we've figured out that the subject we're creating the credential for has the DID `did:key:z6MkmNnvnfzW3nLiePweN3niGLnvp2BjKx3NM186vJ2yRg2z`. Now we have all the set up done we're ready to create our credential.

Construct a `PUT` request to `/v1/credentials` as follows:

```
decentralgabe marked this conversation as resolved.
Show resolved Hide resolved
curl -X PUT localhost:3000/v1/credentials -d '{
"issuer": "did:key:z6Mkm1TmRWRPK6n21QncUZnk1tdYkje896mYCzhMfQ67assD",
"verificationMethodId": "did:key:z6Mkm1TmRWRPK6n21QncUZnk1tdYkje896mYCzhMfQ67assD#z6Mkm1TmRWRPK6n21QncUZnk1tdYkje896mYCzhMfQ67assD",
"subject": "did:key:z6MkmNnvnfzW3nLiePweN3niGLnvp2BjKx3NM186vJ2yRg2z",
"schemaId": "aed6f4f0-5ed7-4d7a-a3df-56430e1b2a88",
"data": {
"firstName": "Satoshi",
"lastName": "Nakamoto"
}
}'
```

Upon success we'll see a response such as:

```json
{
"id": "46bc3d25-6aaf-4f50-99ed-61c4b35f6411",
"fullyQualifiedVerificationMethodId": "did:key:z6Mkm1TmRWRPK6n21QncUZnk1tdYkje896mYCzhMfQ67assD#z6Mkm1TmRWRPK6n21QncUZnk1tdYkje896mYCzhMfQ67assD",
"credential": {
"@context": ["https://www.w3.org/2018/credentials/v1"],
"id": "http://localhost:3000/v1/credentials/46bc3d25-6aaf-4f50-99ed-61c4b35f6411",
"type": ["VerifiableCredential"],
"issuer": "did:key:z6Mkm1TmRWRPK6n21QncUZnk1tdYkje896mYCzhMfQ67assD",
"issuanceDate": "2023-07-28T12:45:15-07:00",
"credentialSubject": {
"id": "did:key:z6MkmNnvnfzW3nLiePweN3niGLnvp2BjKx3NM186vJ2yRg2z",
"firstName": "Satoshi",
"lastName": "Nakamoto"
},
"credentialSchema": {
"id": "aed6f4f0-5ed7-4d7a-a3df-56430e1b2a88",
"type": "JsonSchema2023"
}
},
"credentialJwt": "eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa20xVG1SV1JQSzZuMjFRbmNVWm5rMXRkWWtqZTg5Nm1ZQ3poTWZRNjdhc3NEI3o2TWttMVRtUldSUEs2bjIxUW5jVVpuazF0ZFlramU4OTZtWUN6aE1mUTY3YXNzRCIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2OTA1NzM1MTUsImlzcyI6ImRpZDprZXk6ejZNa20xVG1SV1JQSzZuMjFRbmNVWm5rMXRkWWtqZTg5Nm1ZQ3poTWZRNjdhc3NEIiwianRpIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwL3YxL2NyZWRlbnRpYWxzLzQ2YmMzZDI1LTZhYWYtNGY1MC05OWVkLTYxYzRiMzVmNjQxMSIsIm5iZiI6MTY5MDU3MzUxNSwibm9uY2UiOiIzMGMwNDYxZi1jMWUxLTQwNDctYWUwYS01NjgzMjdkMzY4YTYiLCJzdWIiOiJkaWQ6a2V5Ono2TWttTm52bmZ6VzNuTGllUHdlTjNuaUdMbnZwMkJqS3gzTk0xODZ2SjJ5UmcyeiIsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiXSwiY3JlZGVudGlhbFN1YmplY3QiOnsiZmlyc3ROYW1lIjoiU2F0b3NoaSIsImxhc3ROYW1lIjoiTmFrYW1vdG8ifSwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6ImFlZDZmNGYwLTVlZDctNGQ3YS1hM2RmLTU2NDMwZTFiMmE4OCIsInR5cGUiOiJKc29uU2NoZW1hMjAyMyJ9fX0.xwqpDuO6PDeEqYr6DflbeR6mhuwvVg0uR43i-7Zhy2DdaH1e3Jt4DuiMy09tZQ2jAXki0rjMNgLt7dPpzOl8BA"
}
```

In the `credential` property we see a readable version of the VC. The VC is signed and packaged as a JWT in the `credentialJwt` property. If you're interested, you can decode the JWT using a tool such as [jwt.io](https://jwt.io/). If you were to 'issue' or transmit the credential to a _holder_ you would just send this JWT value.
decentralgabe marked this conversation as resolved.
Show resolved Hide resolved

## Getting Credentials

Once you've created multiple credentials, you can view all credentials by making a `GET` request to `/v1/credentials`. This endpoint also supports three query parameters: `issuer`, `schema`, and `subject` which can be used mutually exclusively.

You can get a single credential by making a `GET` request to `/v1/credentials/{id}`.

## Other Credential Operations

To learn about verifying credentials [read more here](verification.md). You can also learn more about [credential status here](status.md).

13 changes: 4 additions & 9 deletions doc/howto/did.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,18 @@ Upon a successful request you should see a response such as:
}
```

## Creating A DID
## Creating a DID

You can create a DID by sending a `PUT` request to the `/v1/dids/{method}` endpoint. The request body needs two pieces of information: a method and a key type. The method must be supported by the service, and the key type must be supported by the method. You can find out more specifics about what each method supports [by looking at the SDK](https://github.com/TBD54566975/ssi-sdk/tree/main/did). Certain methods may support additional properties in an optional `options` fields.

For now let's keep things simple and create a new `did:key` with the key type [`Ed25519`](https://ed25519.cr.yp.to/), a widely respected key type using [ellicptic curve cryptography](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography).

**Create DID Key Request**

`PUT` to `/v1/dids/key`
Make a `PUT` request to `/v1/dids/key`. A sample CURL command is as follows:

```json
{
"keyType": "Ed25519"
}
```bash
curl -X PUT localhost:3000/v1/dids/key -d '{"keyType": "Ed25519"}'
```

If successful, you should see a response such as...
Expand Down Expand Up @@ -117,6 +115,3 @@ You can get a specific DID's document by making a `GET` request to the method's
## DIDs Outside the Service

The [universal resolver](https://github.com/decentralized-identity/universal-resolver) is a project at the [Decentralized Identity Foundation](https://identity.foundation/) aiming to enable the resolution of _any_ DID Document. The service, when run with [Docker Compose, runs a select number of these drivers (and more can be configured). It's possible to leverage the resolution of DIDs not supported by the service by making `GET` requests to `/v1/dids/resolver/{did}`.



123 changes: 123 additions & 0 deletions doc/howto/schema.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# How To: Create a Schema

## Background

When creating [Verifiable Credentials](https://www.w3.org/TR/vc-data-model) it's useful to have a mechanism to define the shape the data in the credential takes, in a consistent manner. The VC Data Model uses an open world data model, and with it, provides a mechanism to "extend" the core terminology to add any term with a technology known as [JSON-LD](https://json-ld.org/). JSON-LD is responsible for the `@context` property visible in VCs, DIDs, and other documents in the SSI space. However, JSON-LD is focused on _semantics_, answering the question "do we have a shared understanding of what this thing is?" more specifically, for a name credential, does your concept of "name" match mine. Though the core data model is a JSON-LD data model, processing VCs as JSON-LD is not a requirement. The SSI Service chooses to take a simpler approach and [process VCs as pure JSON](https://www.w3.org/TR/vc-data-model/#json).

When constructing and processing VCs as pure JSON it is useful to have a mechanism to define the data and add some light validation onto the shape that data takes. [JSON Schema](https://json-schema.org/) is a widely used, and widely supported toolset that enables such functionalty: the ability to define a schema, which provides a set of properties (both required and optional), and some light validation on top of those properties. The VC Data Model has [a section on data schemas](https://www.w3.org/TR/vc-data-model/#data-schemas) that enables this functionality.

## Intro to JSON Schema with Verifiable Credentials

Making use of the `credentialSchema` property [defined in the VC Data Model](https://www.w3.org/TR/vc-data-model/#data-schemas) TBD and other collaborators in the W3C are working on [a new specification](https://w3c.github.io/vc-json-schema/) which enables a standards-compliant path to using JSON Schema with Verifiable Credentials. The VC JSON Schema specification defines two options for using JSON Schemas: the first, a plan JSON Schema that can apply to _any set of properties_ in a VC, and the second, a Verifiable Credential that wraps a JSON Schema.

In some cases it is useful to package a JSON Schema as a Verifiable Credential to retain information about authorship (who created the schema), when it was created, and enable other features the VC Data Model offers, such as the ability to suspend the usage of a schema with [a status](https://www.w3.org/TR/vc-data-model/#status).

An example email JSON Schema using [JSON Schema Draft 2020-12](https://json-schema.org/draft/2020-12/json-schema-core.html) is provided below:

```json
{
"$id": "https://example.com/schemas/email.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"name": "Email Address",
"type": "object",
"properties": {
"emailAddress": {
"type": "string",
"format": "email"
}
},
"required": ["emailAddress"]
}
```

We can see that the schema defines a property `emailAddress` of JSON type `string`, and it is required. This means that any piece of JSON we apply this schema to will pass if a valid `emailAddress` property is present and fail otherwise.

Now that we have a valid JSON Schema, we'll need to transform it so it's useful in being applied to a Verifiable Credential, not just any arbitrary JSON. We know that we want the presence of an `emailAddress` in the `credentialSubject` property of a VC and adjust the schema accordingly:

```json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"name": "Email Credential",
"type": "object",
"properties": {
"credentialSubject": {
"type": "object",
"properties": {
"emailAddress": {
"type": "string",
"format": "email"
}
},
"required": ["emailAddress"]
}
}
}
```

Now our schema, applied to a Verifiable Credential, will guarantee that the `credentialSubject` property contains a valid `emailAddress` property.

## Creating a Schema

The service exposes a set of APIs for managing schemas. To create a schema you have two options: signed or not. As mentioned earlier, the signed version of a schema is packaged as a Verifiable Credential. To create a signed schema you'll need to pass in two additional properties – the issuer DID and the ID of the verification method to use to sign the schema. We'll keep things simple for now and create an unsigned schema.

After forming a valid JSON Schema, generate a `PUT` request to `/v1/schemas` as follows:

```bash
curl -X PUT localhost:3000/v1/schemas -d '{
"name": "Email Credential",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"credentialSubject": {
"type": "object",
"properties": {
"emailAddress": {
"type": "string",
"format": "email"
}
},
"required": ["emailAddress"]
}
}
}
}'
```

Upon success you'll see a response which includes the schema you passed in, with a service-generated identifier for the schema. You'll also notice a type `JsonSchema2023`, which is defined by the [VC JSON Schema specification](https://w3c.github.io/vc-json-schema/#jsonschema2023):

```json
{
"id": "ebeebf7b-d452-4832-b8d3-0042ec80e108",
"type": "JsonSchema2023",
"schema": {
"$id": "http://localhost:3000/v1/schemas/ebeebf7b-d452-4832-b8d3-0042ec80e108",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"name": "Email Credential",
"properties": {
"credentialSubject": {
"properties": {
"emailAddress": {
"format": "email",
"type": "string"
}
},
"required": [
"emailAddress"
],
"type": "object"
}
},
"type": "object"
}
}
```

Now you're ready to use the schema in [creating a credential](credential.md).

## Getting Schemas

Once you've created multiple schemas, you can view them all by make a `GET` request to the `v1/schemas` endpoint. Future enhancements may enable filtering based on name, author, or other properties.

You can get a specific schema by make a `GET` request to the `v1/schemas/{schemaId}` endpoint.

2 changes: 1 addition & 1 deletion doc/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2788,7 +2788,7 @@ paths:
type: string
summary: Batch Create DIDs
tags:
- CredentialAPI
- DecentralizedIdentityAPI
/v1/dids/resolver/{id}:
get:
consumes:
Expand Down
3 changes: 2 additions & 1 deletion pkg/server/router/did.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/goccy/go-json"
"github.com/pkg/errors"

"github.com/tbd54566975/ssi-service/internal/util"
"github.com/tbd54566975/ssi-service/pkg/server/framework"
"github.com/tbd54566975/ssi-service/pkg/server/pagination"
Expand Down Expand Up @@ -408,7 +409,7 @@ func NewBatchDIDRouter(svc *did.BatchService) *BatchDIDRouter {
// @Summary Batch Create DIDs
// @Description Create a batch of verifiable credentials. The operation is atomic, meaning that all requests will
// @Description succeed or fail. This is currently only supported for the DID method named `did:key`.
// @Tags CredentialAPI
// @Tags DecentralizedIdentityAPI
// @Accept json
// @Produce json
// @Param method path string true "Method. Only `key` is supported."
Expand Down
2 changes: 0 additions & 2 deletions pkg/service/schema/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,6 @@ func (s Service) createCredentialSchema(ctx context.Context, jsonSchema schema.J

// set subject value as the schema
subject := credential.CredentialSubject(jsonSchema)
// TODO(gabe) remove this after https://github.com/TBD54566975/ssi-sdk/pull/404 is merged
subject[credential.VerifiableCredentialIDProperty] = schemaURI
if err := builder.SetCredentialSubject(subject); err != nil {
return nil, sdkutil.LoggingErrorMsgf(err, "could not set subject: %+v", subject)
}
Expand Down