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

docs: OIDC and ConnectionlessOffer examples #294

Merged
merged 1 commit into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 7 additions & 1 deletion demos/next/src/reducers/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,13 +171,19 @@ const appSlice = createSlice({
builder.addCase(sendMessage.pending, (state, action) => {
state.agent.isSendingMessage = true;
state.agent.hasSentMessage = false;
let credentialFormat = SDK.Domain.CredentialType.Unknown;
try {
credentialFormat = action.meta.arg.message.credentialFormat;
}
catch {}

state.messages.push({
...action.meta.arg.message,
isAnswering: true,
hasAnswered: false,
error: null,
body: action.meta.arg.message.body,
credentialFormat: action.meta.arg.message.credentialFormat
credentialFormat
})
})

Expand Down
28 changes: 28 additions & 0 deletions docs/examples/ConnectionlessOffer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Edge SDK Connectionless Credential Offer

## Flow
1. Obtain a Connectionless Credential Offer from an Issuer.

A Connectionless Credential Offer is an Out of Band Invitation with a Credential Offer Attachment.
This should be a URI with a single query parameter `_oob`, which is an encoded JSON.
It should look similar to:

```
https://my.domain.com/path?_oob=eyJpZCI6ImY5NmUzNjk5LTU5MWMtNGFlNy1iNWU2LTZlZmU2ZDI2MjU1YiIsInR5cGUiOiJodHRwczovL2RpZGNvbW0ub3JnL291dC1vZi1iYW5kLzIuMC9pbnZpdGF0aW9uIiwiZnJvbSI6ImRpZDpwZWVyOjIuRXo2TFNmc0tNZTh2U1NXa1lkWkNwbjRZVmlQRVJmZEdBaGRMQUdIZ3gyTEdKd2ZtQS5WejZNa3B3MWtTYWJCTXprQTN2NTl0UUZuaDNGdGtLeTZ4TGhMeGQ5UzZCQW9hQmcyLlNleUowSWpvaVpHMGlMQ0p6SWpwN0luVnlhU0k2SW1oMGRIQTZMeTh4T1RJdU1UWTRMakV1TXpjNk9EQTRNQzlrYVdSamIyMXRJaXdpY2lJNlcxMHNJbUVpT2xzaVpHbGtZMjl0YlM5Mk1pSmRmWDAiLCJib2R5Ijp7ImdvYWxfY29kZSI6Imlzc3VlLXZjIiwiZ29hbCI6IlRlc3QgT09CIiwiYWNjZXB0IjpbImRpZGNvbW0vdjIiXX0sImNyZWF0ZWRfdGltZSI6MTcyNDg1MTEzOSwiZXhwaXJlc190aW1lIjo5OTI0ODUxNDM5LCJhdHRhY2htZW50cyI6W3siaWQiOiIwMGNkYzkwYy05YTk5LTRjZGEtODdmZS00ZjRiMjU5NTExMmEiLCJtZWRpYV90eXBlIjoiYXBwbGljYXRpb24vanNvbiIsImRhdGEiOnsianNvbiI6eyJpZCI6IjY1NWU5YTJjLTQ4ZWQtNDU5Yi1iM2RhLTZiMzY4NjY1NTU2NCIsInR5cGUiOiJodHRwczovL2RpZGNvbW0ub3JnL2lzc3VlLWNyZWRlbnRpYWwvMy4wL29mZmVyLWNyZWRlbnRpYWwiLCJib2R5Ijp7ImdvYWxfY29kZSI6Ik9mZmVyIENyZWRlbnRpYWwiLCJjcmVkZW50aWFsX3ByZXZpZXciOnsidHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvaXNzdWUtY3JlZGVudGlhbC8zLjAvY3JlZGVudGlhbC1jcmVkZW50aWFsIiwiYm9keSI6eyJhdHRyaWJ1dGVzIjpbeyJuYW1lIjoiZmFtaWx5TmFtZSIsInZhbHVlIjoiV29uZGVybGFuZCJ9XX19fSwiYXR0YWNobWVudHMiOlt7ImlkIjoiODQwNDY3OGItOWEzNi00OTg5LWFmMWQtMGY0NDUzNDdlMGUzIiwibWVkaWFfdHlwZSI6ImFwcGxpY2F0aW9uL2pzb24iLCJkYXRhIjp7Impzb24iOnsib3B0aW9ucyI6eyJjaGFsbGVuZ2UiOiJhZDBmNDNhZC04NTM4LTQxZDQtOWNiOC0yMDk2N2JjNjg1YmMiLCJkb21haW4iOiJkb21haW4ifSwicHJlc2VudGF0aW9uX2RlZmluaXRpb24iOnsiaWQiOiI3NDhlZmE1OC0yYmNlLTQ0MGQtOTIxZi0yNTIwYTg0NDY2NjMiLCJpbnB1dF9kZXNjcmlwdG9ycyI6W10sImZvcm1hdCI6eyJqd3QiOnsiYWxnIjpbIkVTMjU2SyJdLCJwcm9vZl90eXBlIjpbXX19fX19LCJmb3JtYXQiOiJwcmlzbS9qd3QifV0sInRoaWQiOiJmOTZlMzY5OS01OTFjLTRhZTctYjVlNi02ZWZlNmQyNjI1NWIiLCJmcm9tIjoiZGlkOnBlZXI6Mi5FejZMU2ZzS01lOHZTU1drWWRaQ3BuNFlWaVBFUmZkR0FoZExBR0hneDJMR0p3Zm1BLlZ6Nk1rcHcxa1NhYkJNemtBM3Y1OXRRRm5oM0Z0a0t5NnhMaEx4ZDlTNkJBb2FCZzIuU2V5SjBJam9pWkcwaUxDSnpJanA3SW5WeWFTSTZJbWgwZEhBNkx5OHhPVEl1TVRZNExqRXVNemM2T0RBNE1DOWthV1JqYjIxdElpd2ljaUk2VzEwc0ltRWlPbHNpWkdsa1kyOXRiUzkyTWlKZGZYMCJ9fX1dfQ==
```


2. Ensure the validity of the Invitation with `Agent.parseInvitation`

`parseInvitation` decodes and validates the encoded Out of Band Invitation, plus attachments, returning an instance of `OutOfBandInvitation` on success. This OutOfBandInvitation will have a single Attachment for the Credential Offer.

```
const oob = await Agent.parseInvitation(rawOob);
elribonazo marked this conversation as resolved.
Show resolved Hide resolved
```

3. Use `Agent.acceptInvitation` to handle the OutOfBandInvitation appropriately.
In this case, with an attached Credential Offer, the Credential Offer Message will be stored in Pluto.

```
await Agent.acceptInvitation(oob)
```
6 changes: 3 additions & 3 deletions docs/examples/ConnectionlessPresentation.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Cross-Platform Edge SDK Verification
# Edge SDK Connectionless Presentation
## Requirements
1. A working Identus Mediator and an Identus Cloud Agent.
2. A holder who already has a JWT Credential issued by a known issuer (prism:did) [Holder A]


> NOTE:
>
> Please follow the [Quick started guide](../../docs/quick-start) to complete steps 1, 2, 3
> Please follow the [Quick started guide](../../docs/quick-start) to complete steps 1, 2


## Flow
Expand Down Expand Up @@ -53,4 +53,4 @@ The Verifier will make this available to the holder in shape of QA code, link, e

2. The holder then opens its the Edge Agent Wallet SDK, "Connections tab" and will pase the invitation link in the field.

Once the invitation is parsed, the user will then be able to see a new Verification request, choose one of the available credentials and send the proof as the verifier requested.
Once the invitation is parsed, the user will then be able to see a new Verification request, choose one of the available credentials and send the proof as the verifier requested.
41 changes: 41 additions & 0 deletions docs/examples/OIDC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Edge SDK Connectionless Credential Offer

## Flow
1. Obtain a Connectionless Credential Offer from an Issuer.

A Credential Offer should be a URI with a single query parameter `credential_offer`, which is an encoded JSON.
It should look similar to:

```
openid-credential-offer://?credential_offer=%7B%22credential_issuer%22%3A%22http%3A%2F%2Flocalhost%3A8090%2Foid4vci%2Fissuers%2F59104e60-3bf1-4e38-be58-4a219acf561b%22%2C%22credential_configuration_ids%22%3A%5B%22Example%22%5D%2C%22grants%22%3A%7B%22authorization_code%22%3A%7B%22issuer_state%22%3A%22aa10127f-c27e-4130-a0ed-659e3e1ad6ae%22%7D%7D%7D
```


2. Ensure the validity of the Offer with `Agent.parseCredentialOffer`

`parseCredentialOffer` decodes and validates the encoded credential_offer returning the JSON on success.

```
const offer = await Agent.parseCredentialOffer(rawOffer);
```

3. Create an AuthorizationRequest with `Agent.resolveCredentialOffer`

`resolveCredentialOffer` takes the parsed Offer, relevant client id and the desired redirect url,
and constructs an AuthorizationRequest. This AuthorizationRequest contains a url that goes to the Authorization Server
where the user can authorize the client to gain an access token.

```
const authRequest = await Agent.resolveCredentialOffer(offer, CLIENT_ID, REDIRECT_URL);
const urlString = authRequest.url.href;
```

4. Retrieve the Credential with `Agent.resolveCredentialRequest`

After successfully authorizing, the user will be redirected to the given redirect url.
Once there we use the full URL plus query parameters, the Offer and the AuthorizationRequest
to gain an access token and request the Credential (these steps are handled by `resolveCredentialRequest`).

```
const credential = await oidcAgent.resolveCredentialRequest(offer, authRequest, { callbackUrl: url });
```
10 changes: 8 additions & 2 deletions docs/examples/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@ Start a verification flow from an Edge Agent (holder wallet) and another holder
[Start tutorial](./SDKVerification.md)


### Connection less presentation
### Connectionless Credential Offer

How to handle a Connectionless Credential Offer.

[Start tutorial](./ConnectionlessOffer.md)

### Connectionless presentation

Trigger the verifier to generate an out of band verification request. It will work exactly as the didcomm connection invitation links

[Start tutorial](./ConnectionlessPresentation.md)
[Start tutorial](./ConnectionlessPresentation.md)
231 changes: 128 additions & 103 deletions docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,121 +3,146 @@ const fs = require('fs')

// @ts-check
const sidebars = {
tutorialsSidebar: [
tutorialsSidebar: [
{
label: 'Introduction',
type: "doc",
id: "sdk/README"
},
{
type: 'category',
label: 'Examples',
link: {
type: 'doc',
id: 'examples/index',
},
items: [
{
label: 'Introduction',
type: "doc",
id: "sdk/README"
type: 'doc',
label: "Backup",
id: 'examples/Backup',
},
{
type: 'category',
label: 'Examples',
link: {
type: 'doc',
id: 'examples/index',
},
items: [
{
type: 'doc',
label: "SDK Verification",
id: 'examples/SDKVerification',
}

]
type: 'doc',
label: "OIDC",
id: 'examples/OIDC',
},
{
type: 'doc',
label: "Verification",
id: 'examples/SDKVerification',
},
{
type: 'category',
label: 'Modules',
link: {
type: 'doc',
id: 'sdk/modules',
type: 'category',
label: 'Connectionless',
items: [
{
type: 'doc',
label: "Credential Offer",
id: 'examples/ConnectionlessOffer',
},
items: [
'sdk/classes/Apollo',
'sdk/classes/Castor',
'sdk/classes/Agent',
'sdk/classes/Mercury',
'sdk/classes/Pollux',
{
type: 'category',
label: 'Domain',
link: {
type: 'doc',
id: 'sdk/modules/Domain',
},
items: fs.readdirSync(path.resolve(__dirname, "./sdk"))
.reduce((menu, file) => {
const fileExtension = file.split(".")
if (fileExtension[fileExtension.length - 1] === "md") {
return menu
} else if (fs.lstatSync(path.resolve(__dirname, "./sdk", file)).isDirectory()) {
const currentFolder = file;
const files = fs.readdirSync(path.resolve(__dirname, "./sdk", currentFolder)).filter((file) => file !== "Domain.md" && file.includes("Domain."));

return [
...menu,
...files.map((filename) => {
{
type: 'doc',
label: "Presentation",
id: 'examples/ConnectionlessPresentation',
},
]
},
]
},
{
type: 'category',
label: 'Modules',
link: {
type: 'doc',
id: 'sdk/modules',
},
items: [
'sdk/classes/Apollo',
'sdk/classes/Castor',
'sdk/classes/Agent',
'sdk/classes/Mercury',
'sdk/classes/Pollux',
{
type: 'category',
label: 'Domain',
link: {
type: 'doc',
id: 'sdk/modules/Domain',
},
items: fs.readdirSync(path.resolve(__dirname, "./sdk"))
.reduce((menu, file) => {
const fileExtension = file.split(".")
if (fileExtension[fileExtension.length - 1] === "md") {
return menu
} else if (fs.lstatSync(path.resolve(__dirname, "./sdk", file)).isDirectory()) {
const currentFolder = file;
const files = fs.readdirSync(path.resolve(__dirname, "./sdk", currentFolder)).filter((file) => file !== "Domain.md" && file.includes("Domain."));

const fixFile = `sdk/${currentFolder}/${filename.replace(".md", "")}`
return {
label: fixFile.replace(`sdk/${currentFolder}/Domain.`, ""),
type: "doc",
id: fixFile
}
return [
...menu,
...files.map((filename) => {

})
]
}
return menu;
}, [])
},
{
type: 'category',
label: 'Reference',
link: {
type: 'generated-index',
title: 'SDK Reference',
description: 'All other exported classes, types, interfaces and references.'
},
items: fs.readdirSync(path.resolve(__dirname, "./sdk"))
.filter((file) => !file.includes("Domain."))
.reduce((menu, file) => {
const fileExtension = file.split(".")
if (fileExtension[fileExtension.length - 1] === "md") {
return menu
} else if (fs.lstatSync(path.resolve(__dirname, "./sdk", file)).isDirectory()) {
const currentFolder = file;
const files = fs.readdirSync(path.resolve(__dirname, "./sdk", currentFolder)).filter((file) => !file.includes("Domain."))
return [
...menu,
...files.map((filename) => {
const fixFile = `sdk/${currentFolder}/${filename.replace(".md", "")}`
return {
label: fixFile.replace(`sdk/${currentFolder}/`, ""),
type: "doc",
id: fixFile
}
const fixFile = `sdk/${currentFolder}/${filename.replace(".md", "")}`
return {
label: fixFile.replace(`sdk/${currentFolder}/Domain.`, ""),
type: "doc",
id: fixFile
}

})
]
}
return menu;
}, [])
}
]
})
]
}
return menu;
}, [])
},
{
type: 'category',
label: 'Decision records',
items: [
{
type: 'doc',
id: 'decisions/sdk-package-release',
}
type: 'category',
label: 'Reference',
link: {
type: 'generated-index',
title: 'SDK Reference',
description: 'All other exported classes, types, interfaces and references.'
},
items: fs.readdirSync(path.resolve(__dirname, "./sdk"))
.filter((file) => !file.includes("Domain."))
.reduce((menu, file) => {
const fileExtension = file.split(".")
if (fileExtension[fileExtension.length - 1] === "md") {
return menu
} else if (fs.lstatSync(path.resolve(__dirname, "./sdk", file)).isDirectory()) {
const currentFolder = file;
const files = fs.readdirSync(path.resolve(__dirname, "./sdk", currentFolder)).filter((file) => !file.includes("Domain."))
return [
...menu,
...files.map((filename) => {
const fixFile = `sdk/${currentFolder}/${filename.replace(".md", "")}`
return {
label: fixFile.replace(`sdk/${currentFolder}/`, ""),
type: "doc",
id: fixFile
}

]
},
]
})
]
}
return menu;
}, [])
}
]
},
{
type: 'category',
label: 'Decision records',
items: [
{
type: 'doc',
id: 'decisions/sdk-package-release',
}

]
},
]
}

module.exports = sidebars
Loading