Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Verifiable Credentials docs #2894

Merged
merged 25 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
keywords: [intermediate, concept, identity, credentials, verifiable credentials]
---

import { MarkdownChipRow } from "/src/components/Chip/MarkdownChipRow";
import useBaseUrl from "@docusaurus/useBaseUrl";

# How it works

<MarkdownChipRow labels={["Intermediate", "Concept"]} />

## Overview

Verifiable credentials (VCs) on ICP rely on Internet Identity (II), which provides different and unlinkable identities for each dapp. A dapp utilizing verifiable credentials can’t ask for a user's credentials from the [issuer](/docs/current/developer-docs/identity/verifiable-credentials/overview#terminology) of the verifiable credential directly. When a [relying party](/docs/current/developer-docs/identity/verifiable-credentials/overview#terminology) wants to obtain a credential from an issuer, it must request it through an [identity provider](/docs/current/developer-docs/identity/verifiable-credentials/overview#terminology) such as Internet Identity.
jessiemongeon1 marked this conversation as resolved.
Show resolved Hide resolved

Internet Identity acts as a communication link between the relying party and issuer API, connecting with the issuer API and asking for the credentials for the user. After receiving the credentials, they are forwarded to the relying party.

<div class="text--center">
<img
src={useBaseUrl("/img/docs/vcs-1.png")}
alt="Verifiable Credential Workflow"
width="800"
/>
</div>

## User's perspective

From the user's perspective, the relying party opens a new window to allow the credential, which is closed when the flow finishes.

<div class="text--center">
<img
src={useBaseUrl("/img/docs/vcs-2.png")}
alt="Verifiable Credential Workflow"
width="800"
/>
</div>

## Developer's perspective

From the developer’s perspective, the interaction between dapps uses window messages and calls to canisters:

1. The user accesses the relying party and starts the process to request credentials. This may be an action such as logging into a dapp or accessing a private service that requires authorization.

2. The relying party starts the flow with Internet Identity (II):

a. The relying party opens a new II window and waits for a window message.

b. The frontend of II sends a window message to start the request process.

c. The relying party replies with the credentials request and issuer data for the request.

3. The II frontend calls the issuer canister to retrieve the consent message.

4. The II frontend shows all the details to the user: the relying party, the consent message, and the issuer URL, then waits for the user action.

5. The user decides whether to allow or revoke the action.

a. If allowed, the II frontend requests the ID alias to the II backend.

6. The II backend calculates an ID alias which is an opaque identifier to keep unlinkability between the issuer and the relying party.

7. The II frontend requests the credential from the issuer API.
jessiemongeon1 marked this conversation as resolved.
Show resolved Hide resolved

8. The issuer receives the request for the credential, validates the call from II, and replies with a verifiable presentation if the user fulfills the credential's requirements.

9. The II frontend receives the credential from the issuer and forwards it to the relying party, closing the window.

10. The relying party verifies the credentials.

<div class="text--center">
<img
src={useBaseUrl("/img/docs/vcs-3.png")}
jessiemongeon1 marked this conversation as resolved.
Show resolved Hide resolved
alt="Verifiable Credential Workflow"
width="800"
/>
</div>

For more details, check out the [specification in Internet Identity’s repository](https://github.com/dfinity/internet-identity/blob/main/docs/vc-spec.md).

## Next steps

- [Learn how to become an issuer](issuer.mdx).

- [Learn how to become a relying party](relying-party.mdx).
168 changes: 168 additions & 0 deletions docs/developer-docs/identity/verifiable-credentials/issuer.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
keywords: [intermediate, tutorial, identity, credentials, verifiable credentials, issuer]
---

import { MarkdownChipRow } from "/src/components/Chip/MarkdownChipRow";
import useBaseUrl from "@docusaurus/useBaseUrl";

# Become an issuer

<MarkdownChipRow labels={["Intermediate", "Tutorial"]} />

## Overview

An **issuer** is a service or app that can issue a verifiable credential (VC) to a user. On ICP, an issuer is an exposed API that recieves calls from an identity provider and does not trigger any workflows itself. To become an issuer, your canister must implement the issuer API as described in [verifiable credential spec](https://github.com/dfinity/internet-identity/blob/main/docs/vc-spec.md).

Issuers receive credentials requests from relying partys through an identity provider such as Internet Identity (II). The end-user must allow or revoke the communication before the credential is issued.

Internet Identity is used as the identity provider in this tutorial.

## Development of the issuer API

The issuer API consists of four endpoints:

1. [`vc_consent_message`](https://github.com/dfinity/internet-identity/blob/main/docs/vc-spec.md#1-consent-message): Responds with a message of consent to be displayed to the user to receive their consent on issuing the credentials.

2. [`derivation_origin`](https://github.com/dfinity/internet-identity/blob/main/docs/vc-spec.md#2-derivation-origin): Returns the URL used to derive the user's principal for the issuer.

3. [`prepare_credential`](https://github.com/dfinity/internet-identity/blob/main/docs/vc-spec.md#3-prepare-credential): Check the validity of the request and prepare the actual credential requested.

4. [`get_credential endpoint`](https://github.com/dfinity/internet-identity/blob/main/docs/vc-spec.md#4-get-credential): Issues the actual credential requested by the user.
jessiemongeon1 marked this conversation as resolved.
Show resolved Hide resolved

### Step 1: Obtain a consent message (`vc_consent_message`)

First, the identity provider sends a request to the issuer API endpoint `vc_consent_message` to get the consent message to show the user. A consent message is text shown to the user to confirm that they allow the issuing of a VC.

An example implementation in Rust can be found below:

```rust
pub fn get_vc_consent_message_en(
credential_spec: &CredentialSpec,
) -> Result<Icrc21ConsentInfo, Icrc21Error> {
match verify_credential_spec(credential_spec) {
Ok(SupportedCredentialType::EarlyAdopter(since_year)) => Ok(Icrc21ConsentInfo {
consent_message: format!("You became an early adopter in {}.", since_year),
language: "en".to_string(),
}),
Ok(SupportedCredentialType::EventAttendance(event_name)) => Ok(Icrc21ConsentInfo {
consent_message: format!("You have attended the event {}.", event_name),
language: "en".to_string(),
}),
Err(err) => Err(Icrc21Error::ConsentMessageUnavailable(Icrc21ErrorInfo {
description: format!("Credential spec not supported: {:?}", err),
})),
}
}
```

### Step 2: Implement a derivation origin (`derivation_origin`)

Next, the issuer API endpoint `derivation_origin` is called by the identity provider to obtain a URL to be used as the derivation origin for user's principal.

If the issuer doesn't rely on alternative derivation origins, then it must return the canister's URL: `https://<issuer-canister-id>.icp0.io`.

If the issuer relies on the [alternative derivation origins](/docs/current/references/ii-spec#alternative-frontend-origins) feature, the endpoint must return the same value for the `derivationOrigin` when logging in.

The returned value is subject to verification via .well-known/ii-alternative-origins, as describe in the alternative origins documentation.
jessiemongeon1 marked this conversation as resolved.
Show resolved Hide resolved


An example implementation in Rust can be found below:

```rust
use ic_cdk::update;
use vc_util::issuer_api::{DerivationOriginData, DerivationOriginError, DerivationOriginRequest};

#[update(name = "derivation_origin")]
async fn vc_derivation_origin(
_req: DerivationOriginRequest,
) -> Result<DerivationOriginData, DerivationOriginError> {
let dfx_network = option_env!("DFX_NETWORK").unwrap();
let origin = match dfx_network {
"local" => format!("http://{}.localhost:4943", ic_cdk::api::id()),
"ic" => format!("https://{}.icp0.io", ic_cdk::api::id()),
_ => {
return Err(DerivationOriginError::Internal(
"Invalid DFX_NETWORK".to_string(),
))
}
};
Ok(DerivationOriginData { origin })
}
```

:::info
The returned derivation origin is subject to verification via `.well-known/ii-alternative-origins`, as described in the [feature description](https://internetcomputer.org/docs/current/references/ii-spec#alternative-frontend-origins).
:::

### Step 3: Prepare the credentials (`prepare_credential`)

Before a credential can be issued, the request for the credential must be checked for validity using the `prepare_credential` API endpoint. The objective of this endpoint is to check the validity of the request and update the `certified_data` with a new root hash that includes the signature on the credential. Upon success, the actual credential is prepared.

For more details on how to validate the request or create the actual credential, check out the [VC specification](https://github.com/dfinity/internet-identity/blob/main/docs/vc-spec.md).

An example implementation can be found in the [verifiable credentials playground example](https://github.com/dfinity/vc-playground/blob/b2f8cd5f5397b7b355b6503df5af3789834b79e9/issuer/src/main.rs#L557).

:::info
The value of `prepared_context` is used to transfer information between the `prepare_credential` and `get_credential` steps. It is up to the issuer API to decide on the content of this field since the issuer API creates `prepared_context` and is the only entity that consumes it.

For example, when using [canister signatures](https://internetcomputer.org/docs/current/references/ic-interface-spec#canister-signatures)
`prepared_context` contains a time stamped and unsigned VC, for which the canister signature will be available through the `get_credential` call.
:::

### Step 4: Issue the credential (`get_credential`)

Lastly, the issuer API endpoint `get_credential` is used to issue the credential requested by the user. The same checks used to prepare the credential are ran again, with an additional verify step to confirm that `prepared_context` is consistent with `prepare_credential`. If successful, the issuer API returns the signed credential in JWS-format.
jessiemongeon1 marked this conversation as resolved.
Show resolved Hide resolved

An example implementation can be found in the [verifiable credentials playground example](https://github.com/dfinity/vc-playground/blob/b2f8cd5f5397b7b355b6503df5af3789834b79e9/issuer/src/main.rs#L557).

## Recommended conventions

An issuer may follow the convention below for an easier verification of the returned credentials.

Given a credential specification such as:

```
"credentialSpec": {
"credentialType": "SomeVerifiedProperty",
"arguments": {
"argument_1": "value_1",
"another_argument": 42,
}
```

The returned JWT should contain a property named by the value of `credentialType` in `credentialSubject` from the specification, with key-value entries listing the arguments from the specification, namely:

```
"SomeVerifiedProperty": {
"argument_1": "value_1",
"another_argument": 42,
}
```

For example, for a `VerifiedAdult` credential, you would use the following credential specification:

```
"credentialSpec": {
"credentialType": "VerifiedAdult",
"arguments": {
"minAge": 18,
}
```

A compliant issuer would issue a VC that contains `credentialSubject` with the property:

```
"VerifiedAdult": {
"minAge": 18,
}
```

## Resources

- [Verifiable credentials specification](https://github.com/dfinity/internet-identity/blob/main/docs/vc-spec.md).

- [Relying party and issuer demo](https://github.com/dfinity/vc-playground/blob/main/issuer/src/main.rs).

- [Verifiable credentials playground: Issuer](https://metaissuer.vc/).

- [Verifiable credentials playground: Relying party](https://relyingparty.vc/).
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
keywords: [intermediate, concept, identity, credentials, verifiable credentials]
---

import { MarkdownChipRow } from "/src/components/Chip/MarkdownChipRow";

# Overview

<MarkdownChipRow labels={["Intermediate", "Concept"]} />

A credential is a document or certificate that validates an individual's identity or qualifications. Credentials are a part of daily life, with common examples including:

- A driver's license that qualifies an individual to operate a motor vehicle.
- A university degree that can be used to assert a level of education.
- A government-issued passport enabling travel between countries.

These are examples of physical credentials, as they have a physical component that must be presented for validation. Credentials can also be digital, relying on authentication using cryptographic signatures such as canister signatures on ICP.

Verifiable credentials (VCs) are a type of digital credential that enables individuals, organizations, or things (such as devices) cryptographically.

The technical implementation of VCs on ICP can be found in the [specification](https://github.com/dfinity/internet-identity/blob/main/docs/vc-spec.md). It is recommended you first read the rest of this documentation, as it includes technical details.

## Benefits

Verifiable credentials are designed to be tamper-evident, privacy-preserving, and interoperable across different systems and contexts. By using verifiable credentials, you will have a mechanism to express these sorts of credentials on ICP in a way that is cryptographically secure, privacy-preserving, and machine-verifiable.
jessiemongeon1 marked this conversation as resolved.
Show resolved Hide resolved

## Terminology
jessiemongeon1 marked this conversation as resolved.
Show resolved Hide resolved

When learning about and using VCs, there are two primary terms to familiarize yourself with:

- **User**: Users earn credentials, a piece of data that certifies information about the user, from an issuer.

- **Issuer**: An issuer is an entity (a dapp, organization, government, etc.) that verifies information about the user.

- **Relying party**: A different dapp (organization, government, etc.) which requests certified credentials for that user from the issuer.

- **Identity provider**: Entity that (in this case, Internet Identity) creates a temporary identifier for the user when the issuer passes the credential to the relying party, so that the relying party and the issuer never learn the user's identifiers on the other entity's service.

## How to use verifiable credentials

To use verifiable credentials there are two workflows. First, you can [become an issuer](issuer.mdx) of verifiable credentials. By issuing verifiable credentials, you can empower users to control and share their credentials selectively, enhancing privacy and giving users greater autonomy over their digital identity.

The second workflow allows you to [become a relying party](relying-party.mdx) for verifiable credentials. By requiring verifiable credentials from your application's users, you can ensure that the claims that users make are verified by parties (issuers) that you trust, while preserving the user’s privacy.

## Next steps

- [Learn how verifiable credentials work](how-it-works.mdx).

- [Learn how to become an issuer](issuer.mdx).

- [Learn how to become a relying party](relying-party.mdx).
Loading
Loading