Skip to content

Commit 187839a

Browse files
committed
chore: merge openid federation
Signed-off-by: Henrique Dias <mail@hacdias.com>
1 parent 2d7314a commit 187839a

File tree

105 files changed

+6843
-716
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+6843
-716
lines changed

.changeset/big-meals-raise.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@credo-ts/drizzle-storage": minor
3+
"@credo-ts/openid4vc": minor
4+
---
5+
6+
Adds support for chained authorization code flows within the OpenID4VCI credential issuance. This means that external authorization servers can be leveraged to authenticate or identify the user. The access token from this external authorization server can be then used during the issuance process in order to, for example, fetch credential data from an external resource server.

.changeset/fluffy-papers-happen.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@credo-ts/openid4vc": minor
3+
---
4+
5+
refactor(openid4vc): the OpenID4VC module now requires a top-level `app` property instead of a `router` for the `OpenId4VcVerifierModule` and `OpenId4VcIssuerModule`.
6+
7+
Using the `app` directly simplifies the setup, as you don't have to register the routers at the correct paths anymore on your express app.
8+
9+
We do recommend that you register your custom routes AFTER the Credo OpenID4VC routes have been registered, to ensure your custom middleware does not clash with Credo's routes.
10+
11+
The reason for changing the router to an `app` is that we need to host files at the top-level `.well-known` path of the server, which is not easily doable with the custom router approach.
12+
13+
If no app is provided, and the issuer or verifier module is enabled, a new app instance will be created.

.changeset/proud-dodos-remember.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@credo-ts/webvh": patch
3+
---
4+
5+
feat(webvh): support AnonCreds object registration (schema, credential definition, revocation definition, revocation status lists)

.changeset/thirty-crews-retire.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@credo-ts/anoncreds": patch
3+
"@credo-ts/didcomm": patch
4+
---
5+
6+
feat: support DIDComm Out of Band proof proposals

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ See [Supported Features](https://credo.js.org/guides/features) on the Credo webs
5151

5252
- 🏃 **Platform agnostic** - out of the box support for Node.JS and React Native
5353
- 🔒 **DIDComm and AIP** - Support for [DIDComm v1](https://hyperledger.github.io/aries-rfcs/latest/concepts/0005-didcomm/), and both v1 and v2 of the [Aries Interop Profile](https://github.com/hyperledger/aries-rfcs/blob/main/concepts/0302-aries-interop-profile/README.md).
54-
- 🛂 **Extendable [DID](https://www.w3.org/TR/did-core/) resolver and registrar** - out of the box support for `did:web`, `did:key`, `did:jwk`, `did:peer`, `did:sov`, `did:indy`, `did:cheqd` and `did:hedera`.
54+
- 🛂 **Extendable [DID](https://www.w3.org/TR/did-core/) resolver and registrar** - out of the box support for `did:web`, `did:webvh`, `did:key`, `did:jwk`, `did:peer`, `did:sov`, `did:indy`, `did:cheqd` and `did:hedera`.
5555
- 🔑 **[OpenID4VC](https://openid.net/sg/openid4vc/)** - support for [OpenID for Verifiable Credential Issuance](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html), [OpenID for Verifiable Presentations](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html) and [Self-Issued OpenID Provider v2](https://openid.net/specs/openid-connect-self-issued-v2-1_0.html).
5656
- 🪪 **Multiple credential formats** - [W3C Verifiable Credential Data Model v1.1](https://www.w3.org/TR/vc-data-model/), [SD-JWT VCs](https://www.ietf.org/archive/id/draft-ietf-oauth-sd-jwt-vc-03.html), and [AnonCreds](https://hyperledger.github.io/anoncreds-spec/).
5757
- 🏢 **Multi-tenant** - Optional multi-tenant module for managing multiple tenants under a single agent.

demo-openid/README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Alice, a former student of Faber College, connects with the College, is issued a
77
## Features
88

99
- ✅ Issuing a credential without authorization (pre-authorized code flow).
10-
- ✅ Issuing a credenital with external authorization server (authorization code flow)
10+
- ✅ Issuing a credential with external authorization server (authorization code flow)
1111
- ✅ Resolving a credential offer.
1212
- ✅ Accepting a credential offer.
1313
- ✅ Requesting a credential presentation.
@@ -135,3 +135,20 @@ This will open three proxies. You should then run your demo environments with th
135135
- `PROVIDER_HOST=https://d404-123-123-123-123.ngrok-free.app ISSUER_HOST=https://d738-123-123-123-123.ngrok-free.app pnpm provider` (ngrok url for port 3042)
136136
- `PROVIDER_HOST=https://d404-123-123-123-123.ngrok-free.app ISSUER_HOST=https://d738-123-123-123-123.ngrok-free.app pnpm issuer` (ngrok url for port 2000)
137137
- `VERIFIER_HOST=https://1d91-123-123-123-123.ngrok-free.app pnpm verifier` (ngrok url for port 4000)
138+
139+
### Optional Google Account API for Chained Identity
140+
141+
You can also configure external identity providers in order to be able to use their access tokens to fetch specific data for credentials. In this demo, we have an integration with Google Account OpenID Connect API, which provides an ID Token with information we then use to put on the credential itself.
142+
143+
To set this up, you need to create an account in [Google Cloud](https://console.cloud.google.com/auth/overview) platform, and configure a client with the correct domain. In this case, you need a proxy since the URL is not allowed to be `localhost`.
144+
145+
In addition, the following scopes are necessary:
146+
147+
- `openid`
148+
- `https://www.googleapis.com/auth/userinfo.email`
149+
150+
Once you have the client ID and client secret from the Google integration, please start the issuer as follows:
151+
152+
```sh
153+
ISSUER_HOST="<issuer-host>" GOOGLE_CLIENT_ID="<google-client-id>" GOOGLE_CLIENT_SECRET="<google-client-secret>" pnpm issuer
154+
```

demo-openid/src/BaseAgent.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export class BaseAgent<AgentModules extends ModulesMap> {
2626
}: {
2727
port: number
2828
name: string
29-
modules: AgentModules
29+
modules: (app: Express) => AgentModules
3030
}) {
3131
this.name = name
3232
this.port = port
@@ -42,7 +42,7 @@ export class BaseAgent<AgentModules extends ModulesMap> {
4242
this.agent = new Agent({
4343
config,
4444
dependencies: agentDependencies,
45-
modules,
45+
modules: modules(this.app),
4646
})
4747
}
4848

demo-openid/src/Holder.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
X509Module,
1616
} from '@credo-ts/core'
1717
import type {
18+
OpenId4VciDpopRequestOptions,
1819
OpenId4VciMetadata,
1920
OpenId4VciResolvedCredentialOffer,
2021
OpenId4VpResolvedAuthorizationRequest,
@@ -26,18 +27,21 @@ import {
2627
preAuthorizedCodeGrantIdentifier,
2728
} from '@credo-ts/openid4vc'
2829
import { askar } from '@openwallet-foundation/askar-nodejs'
30+
import type { Express } from 'express'
2931
import { BaseAgent } from './BaseAgent'
3032
import { greenText, Output } from './OutputClass'
3133

3234
function getOpenIdHolderModules(askarStorageConfig: AskarModuleConfigStoreOptions) {
33-
return {
35+
return (app: Express) => ({
3436
askar: new AskarModule({ askar, store: askarStorageConfig }),
35-
openid4vc: new OpenId4VcModule(),
37+
openid4vc: new OpenId4VcModule({
38+
app,
39+
}),
3640
x509: new X509Module({
3741
getTrustedCertificatesForVerification: (_agentContext, { certificateChain, verification }) => {
3842
console.log(
3943
greenText(
40-
`dyncamically trusting certificate ${certificateChain[0].getIssuerNameField('C')} for verification of ${
44+
`dynamically trusting certificate ${certificateChain[0].getIssuerNameField('C')} for verification of ${
4145
verification.type
4246
}`,
4347
true
@@ -47,10 +51,10 @@ function getOpenIdHolderModules(askarStorageConfig: AskarModuleConfigStoreOption
4751
return [certificateChain[0].toString('pem')]
4852
},
4953
}),
50-
} as const
54+
})
5155
}
5256

53-
export class Holder extends BaseAgent<ReturnType<typeof getOpenIdHolderModules>> {
57+
export class Holder extends BaseAgent<ReturnType<ReturnType<typeof getOpenIdHolderModules>>> {
5458
public client = {
5559
clientId: 'wallet',
5660
redirectUri: 'http://localhost:3000/redirect',
@@ -87,7 +91,7 @@ export class Holder extends BaseAgent<ReturnType<typeof getOpenIdHolderModules>>
8791
credentialsToRequest: string[]
8892
) {
8993
const grants = resolvedCredentialOffer.credentialOfferPayload.grants
90-
// TODO: extend iniateAuthorization in oid4vci lib? Or not?
94+
// TODO: extend initiateAuthorization in oid4vci lib? Or not?
9195
if (grants?.[preAuthorizedCodeGrantIdentifier]) {
9296
return {
9397
authorizationFlow: 'PreAuthorized',
@@ -130,6 +134,7 @@ export class Holder extends BaseAgent<ReturnType<typeof getOpenIdHolderModules>>
130134
code?: string
131135
redirectUri?: string
132136
txCode?: string
137+
dpop?: OpenId4VciDpopRequestOptions
133138
}
134139
) {
135140
const tokenResponse = await this.agent.openid4vc.holder.requestToken(
@@ -140,10 +145,12 @@ export class Holder extends BaseAgent<ReturnType<typeof getOpenIdHolderModules>>
140145
codeVerifier: options.codeVerifier,
141146
code: options.code,
142147
redirectUri: options.redirectUri,
148+
dpop: options.dpop,
143149
}
144150
: {
145151
resolvedCredentialOffer,
146152
txCode: options.txCode,
153+
dpop: options.dpop,
147154
}
148155
)
149156

demo-openid/src/HolderInquirer.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { MdocRecord, SdJwtVcRecord, W3cCredentialRecord, W3cV2CredentialRec
22
import { Mdoc } from '@credo-ts/core'
33
import type {
44
OpenId4VciCredentialConfigurationsSupportedWithFormats,
5+
OpenId4VciDpopRequestOptions,
56
OpenId4VciResolvedCredentialOffer,
67
OpenId4VpResolvedAuthorizationRequest,
78
} from '@credo-ts/openid4vc'
@@ -153,6 +154,7 @@ export class HolderInquirer extends BaseInquirer {
153154
let authorizationCode: string | undefined
154155
let codeVerifier: string | undefined
155156
let txCode: string | undefined
157+
let dpop: OpenId4VciDpopRequestOptions | undefined
156158

157159
if (resolvedAuthorization.authorizationFlow === 'Oauth2Redirect') {
158160
console.log(redText('Authorization required for credential issuance', true))
@@ -164,12 +166,11 @@ export class HolderInquirer extends BaseInquirer {
164166
if (req.query.code) {
165167
resolve(req.query.code as string)
166168
// Store original routes
167-
const originalStack = this.holder.app._router.stack
169+
const originalStack = this.holder.app.router.stack
168170

169171
// Remove specific GET route by path
170-
this.holder.app._router.stack = originalStack.filter(
171-
(layer: { route?: { path: string; methods: { get?: unknown } } }) =>
172-
!(layer.route && layer.route.path === '/redirect' && layer.route.methods.get)
172+
this.holder.app.router.stack = originalStack.filter(
173+
(layer) => !(layer.route && layer.route.path === '/redirect')
173174
)
174175
res.send('Success! You can now go back to the terminal')
175176
} else {
@@ -184,6 +185,7 @@ export class HolderInquirer extends BaseInquirer {
184185
console.log('\n\n')
185186
codeVerifier = resolvedAuthorization.codeVerifier
186187
authorizationCode = await code
188+
dpop = resolvedAuthorization.dpop
187189
console.log(greenText('Authorization complete', true))
188190
} else if (resolvedAuthorization.authorizationFlow === 'PresentationDuringIssuance') {
189191
console.log(redText('Presentation during issuance not supported yet', true))
@@ -203,6 +205,7 @@ export class HolderInquirer extends BaseInquirer {
203205
code: authorizationCode,
204206
redirectUri: authorizationCode ? this.holder.client.redirectUri : undefined,
205207
txCode,
208+
dpop,
206209
})
207210

208211
console.log(greenText('Received and stored the following credentials.', true))

0 commit comments

Comments
 (0)