Skip to content

Commit

Permalink
docs: oid4vci example and docs [skip ci] (#1265)
Browse files Browse the repository at this point in the history
Signed-off-by: Pat Losoponkul <[email protected]>
Signed-off-by: patlo-iog <[email protected]>
Signed-off-by: Hyperledger Bot <[email protected]>
Co-authored-by: Yurii Shynbuiev - IOHK <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Hyperledger Bot <[email protected]>
  • Loading branch information
4 people authored Jul 16, 2024
1 parent d22745f commit f999f30
Show file tree
Hide file tree
Showing 30 changed files with 321 additions and 170 deletions.
2 changes: 1 addition & 1 deletion docs/docusaurus/credentials/issue.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Issue credentials
# Issue credentials (DIDComm)

In the Identus Platform, the [Issue Credentials Protocol](/docs/concepts/glossary#issue-credentials-protocol) allows you to create, retrieve, and manage issued [verifiable credentials (VCs)](/docs/concepts/glossary#verifiable-credentials) between a VC issuer and a VC holder.

Expand Down
74 changes: 74 additions & 0 deletions docs/docusaurus/credentials/oid4vci.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Issue credentials (OID4VCI)

[OID4VCI](/docs/concepts/glossary#oid4vci) (OpenID for Verifiable Credential Issuance) is a protocol that extends OAuth2 to issue credentials.
It involves a Credential Issuer server and an Authorization server working together,
using the authorization and token endpoints on the Authorization Server to grant holders access to credentials on the Credential Issuer server.
These servers may or may not be the same, depending on the implementation.

The Identus Cloud Agent can act as a Credential Issuer server and integrate with any Authorization Server that follows the integration contract. The contract for the Authorization Server in the OID4VCI flow can be found [here](https://github.com/hyperledger/identus-cloud-agent/blob/main/docs/general/authserver-oid4vci-contract.md).

## Example: OID4VCI Authorization Code Issuance

Example is available [here](https://github.com/hyperledger/identus-cloud-agent/tree/main/examples/st-oid4vci).

Following the instructions, the example demonstrates a single-tenant agent setup using an external Keycloak as the Issuer Authorization Server. The demo application walks through the authorization code issuance flow step-by-step.

#### 1. Launching Local Example Stack

```bash
docker-compose up
```

After running the `docker-compose up` command, all the containers should be running and initialized with the necessary configurations. The following logs should appear indicating that the stack is ready to execute the flow

```
_ _ _ _ _
| |_| |_| |_ _ __| | | ___
| ' \ _| _| '_ \_ _(_-<
|_||_\__|\__| .__/ |_|/__/
|_|
2024-07-16_11:51:01.301 INFO o.h.b.s.BlazeServerBuilder@L424:[ZScheduler-Worker-5] {} - http4s v0.23.23 on blaze v0.23.15 started at http://0.0.0.0:8085/
```

#### 2. Building the demo application

```bash
docker build -t identus-oid4vci-demo:latest ./demo
```

#### 3. Running the demo application

```bash
docker run --network <NETWORK_NAME> -it identus-oid4vci-demo:latest
```
The parameter `NETWORK_NAME` should be the same as the network name in docker-compose.
This name can be discovered by running the `docker network ls` command.

The demo application acts as both issuer and Holder in the same script.
See the source code for detailed steps on how to implement this flow.
The demo application will interactively prompt the next step in the issuance flow.
Keep continuing until this log appears asking the user to log in using the browser.

```
##############################
Open this link in the browser to login
http://localhost:9980/realms/students/protocol/openid-connect/auth?redirect_uri=.....
##############################
wating for authorization redirect ...
```

Open this URL in the browser. Enter `alice` for the username and `1234` for the password.

After a successful login, this log should appear indicating the demo application has received the credentials.

```
::::: Credential Received :::::
{
"credential": "eyJ0eXAiOiJKV1QiLC...SK1vJK-fx6zjXw"
}
```
5 changes: 3 additions & 2 deletions docs/docusaurus/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ const sidebars = {
},
items: [
'credentials/issue',
'credentials/oid4vci',
'credentials/present-proof',
'credentials/revocation',
'credentials/revocation'
]
},
{
Expand Down Expand Up @@ -96,7 +97,7 @@ const sidebars = {
'multitenancy/tenant-onboarding-ext-iam',
'multitenancy/tenant-onboarding-self-service',
'multitenancy/tenant-migration',
'multitenancy/admin-authz-ext-iam',
'multitenancy/admin-authz-ext-iam'
]
}
]
Expand Down
72 changes: 72 additions & 0 deletions docs/general/authserver-oid4vci-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# OID4VCI Authorization Server contract

Identus Cloud Agent supports OID4VCI while allowing users to plug-in their authorization server.
The agent provides a credential endpoint, while the authorization server handles the authorization and token endpoints.
This flexibility enables integration with any existing authorization server potentially containing the holder user base.
The issuance flow implementation requires the authorization server to adhere to the contract, ensuring the agent can manage the issuance session and coordinate the process.

The Identus platform also provides the [Keycloak plugin reference implementation](https://github.com/hyperledger/identus-keycloak-plugins) showcasing the agent capability.
However, the authorization server is not limited to only Keycloak.

## Contract for Authorization Code issuance flow

The sequence diagram is largely based on [OID4VCI spec](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-authorization-code-flow)
with slight modification to the __TokenEndpoint__.

```mermaid
sequenceDiagram
participant Holder
participant Issuer
participant AuthServer
participant CloudAgent
Issuer ->>+ CloudAgent: Create CredentialOffer
CloudAgent ->>- Issuer: CredentialOffer<br>(issuer_state)
Issuer -->> Holder: Present offer<br>(issuer_state)
Holder ->>+ CloudAgent: Discover Metadata
CloudAgent ->>- Holder: IssuerMetadata
Holder ->>+ AuthServer: Discover Metadata
AuthServer ->>- Holder: AuthServerMetadata
Holder ->>+ AuthServer: AuthorizationRequest<br>(issuer_state)
AuthServer ->>- Holder: AuthorizationResponse<br>(code)
Holder ->>+ AuthServer: TokenRequest<br>(code)
AuthServer ->>+ CloudAgent: NonceRequest<br>(issuer_state)
CloudAgent ->>- AuthServer: NonceResponse<br>(c_nonce)
AuthServer ->>- Holder: TokenResponse<br>(c_nonce)
Holder ->>+ CloudAgent: CredentialRequest<br>(proof)
CloudAgent ->>- Holder: CredentialResponse
```


### Authorization Endpoint

1. Authorization `scope` MUST be configured in the Authorization Server to the same value as in Credential Issuer Metadata
2. The endpoint MUST accept the parameter `issuer_state` in the [__AuthorizationRequest__](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#section-5.1.3-2.3) and recall this value in the subsequent call on the __TokenEndpoint__

### Token Endpoint

1. When the holder makes a __TokenRequest__ to the __TokenEndpoint__, the __AuthorizationServer__ MUST recall the `issuer_state` parameter and make an HTTP call to the `/oid4vci/nonces` endpoint in the Cloud Agent using the following format.

__NonceRequest__

```
POST /oid4vci/nonces
Authorization: Bearer <JWT_TOKEN>
{
"issuerState": "<ISSUER_STATE>"
}
```
Where `JWT_TOKEN` is a valid token issued by the __AuthorizationServer__.

__NonceResponse__

```
{
"nonce": "<NONCE>",
"nonceExpiresIn": <NONCE_EXPIRES_IN>
}
```

2. The [__TokenResponse__](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-successful-token-response) must include `c_nonce` and `c_nonce_expires_in` parameter in the __TokenResponse__

2 changes: 1 addition & 1 deletion examples/.nickel/caddy.ncl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ in
handle_path /didcomm* {
reverse_proxy %{args.agent.host}:%{std.to_string args.agent.didcommPort}
}
handle_path /agent* {
handle_path /cloud-agent* {
reverse_proxy %{args.agent.host}:%{std.to_string args.agent.restPort}
}
handle_path /keycloak* {
Expand Down
2 changes: 1 addition & 1 deletion examples/.nickel/root.ncl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ in
name = "issuer",
port = 9980,
realm = "students",
extraEnvs = { IDENTUS_URL = "http://caddy-issuer:8080/prism-agent" }
extraEnvs = { IDENTUS_URL = "http://caddy-issuer:8080/cloud-agent" }
}
),

Expand Down
2 changes: 1 addition & 1 deletion examples/.nickel/stack.ncl
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ in
agentDb = makeSharedDbConfig "agent",
node = { host = "node" },
didcommServiceUrl = "http://%{hosts.caddy}:%{std.to_string args.port}/didcomm",
restServiceUrl = "http://%{hosts.caddy}:%{std.to_string args.port}/agent",
restServiceUrl = "http://%{hosts.caddy}:%{std.to_string args.port}/cloud-agent",
apikeyEnabled = args.apikeyEnabled,
}
& (
Expand Down
2 changes: 1 addition & 1 deletion examples/.nickel/versions.ncl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
# identus
agent = "1.37.0",
agent = "1.38.0",
node = "2.4.0",
identusKeycloak = "0.2.0",
# 3rd party
Expand Down
2 changes: 1 addition & 1 deletion examples/mt-keycloak-vault/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

| Exposed Service | Description |
|---------------------------------|--------------------------|
| `localhost:8080/prism-agent` | Multi-tenant Cloud Agent |
| `localhost:8080/cloudagent` | Multi-tenant Cloud Agent |
| `localhost:8080/keycloak/admin` | Keycloak |
| `localhost:8200` | Vault |

Expand Down
8 changes: 4 additions & 4 deletions examples/mt-keycloak-vault/compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ configs:
handle_path /didcomm* {
reverse_proxy agent-default:8090
}
handle_path /agent* {
handle_path /cloud-agent* {
reverse_proxy agent-default:8085
}
handle_path /keycloak* {
Expand Down Expand Up @@ -46,14 +46,14 @@ services:
POLLUX_DB_PASSWORD: postgres
POLLUX_DB_PORT: '5432'
POLLUX_DB_USER: postgres
POLLUX_STATUS_LIST_REGISTRY_PUBLIC_URL: http://caddy-default:8080/agent
POLLUX_STATUS_LIST_REGISTRY_PUBLIC_URL: http://caddy-default:8080/cloud-agent
PRISM_NODE_HOST: node
PRISM_NODE_PORT: '50053'
REST_SERVICE_URL: http://caddy-default:8080/agent
REST_SERVICE_URL: http://caddy-default:8080/cloud-agent
SECRET_STORAGE_BACKEND: vault
VAULT_ADDR: http://vault-default:8200
VAULT_TOKEN: admin
image: ghcr.io/hyperledger/identus-cloud-agent:1.37.0
image: ghcr.io/hyperledger/identus-cloud-agent:1.38.0
restart: always
caddy-default:
configs:
Expand Down
6 changes: 3 additions & 3 deletions examples/mt-keycloak-vault/hurl/01_create_users.hurl
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ HTTP 200
issuer_access_token: jsonpath "$.access_token"

# Create Issuer wallet
POST {{ agent_url }}/agent/wallets
POST {{ agent_url }}/cloud-agent/wallets
Authorization: Bearer {{ issuer_access_token }}
{
"name": "issuer-wallet"
Expand All @@ -85,7 +85,7 @@ HTTP 200
holder_access_token: jsonpath "$.access_token"

# Create Holder wallet
POST {{ agent_url }}/agent/wallets
POST {{ agent_url }}/cloud-agent/wallets
Authorization: Bearer {{ holder_access_token }}
{
"name": "holder-wallet"
Expand All @@ -104,7 +104,7 @@ HTTP 200
verifier_access_token: jsonpath "$.access_token"

# Create Verifier wallet
POST {{ agent_url }}/agent/wallets
POST {{ agent_url }}/cloud-agent/wallets
Authorization: Bearer {{ verifier_access_token }}
{
"name": "verifier-wallet"
Expand Down
Loading

0 comments on commit f999f30

Please sign in to comment.