Skip to content

Commit b7a0808

Browse files
authored
Merge pull request #114 from Sphereon-Opensource/develop
New release
2 parents 4d46a72 + a0d8ad3 commit b7a0808

98 files changed

Lines changed: 10276 additions & 4021 deletions

File tree

Some content is hidden

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

lerna.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"packages": ["packages/*"],
3-
"version": "0.10.3",
3+
"version": "0.11.0",
44
"npmClient": "pnpm",
55
"command": {
66
"publish": {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sphereon/oid4vci-workspace",
3-
"version": "0.5.0",
3+
"version": "0.11.0",
44
"description": "OpenID for Verifiable Credential Issuance workspace",
55
"author": "Sphereon",
66
"license": "Apache-2.0",

packages/callback-example/lib/IssuerCallback.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Ed25519Signature2020 } from '@digitalcredentials/ed25519-signature-2020
33
import { Ed25519VerificationKey2020 } from '@digitalcredentials/ed25519-verification-key-2020'
44
import { securityLoader } from '@digitalcredentials/security-document-loader'
55
import vc from '@digitalcredentials/vc'
6-
import { CredentialRequestV1_0_11 } from '@sphereon/oid4vci-common'
6+
import { CredentialRequest, CredentialRequestV1_0_11 } from '@sphereon/oid4vci-common'
77
import { CredentialIssuanceInput } from '@sphereon/oid4vci-issuer'
88
import { CompactSdJwtVc, W3CVerifiableCredential } from '@sphereon/ssi-types'
99

@@ -15,7 +15,7 @@ export const generateDid = async () => {
1515
}
1616

1717
// eslint-disable-next-line @typescript-eslint/no-explicit-any
18-
export const getIssuerCallback = (credential: CredentialIssuanceInput, keyPair: any, verificationMethod: string) => {
18+
export const getIssuerCallbackV1_0_11 = (credential: CredentialIssuanceInput, keyPair: any, verificationMethod: string) => {
1919
if (!credential) {
2020
throw new Error('A credential needs to be provided')
2121
}
@@ -33,6 +33,32 @@ export const getIssuerCallback = (credential: CredentialIssuanceInput, keyPair:
3333
return await vc.issue({ credential, suite, documentLoader })
3434
}
3535
}
36+
37+
export const getIssuerCallbackV1_0_13 = (
38+
credential: CredentialIssuanceInput,
39+
credentialRequest: CredentialRequest,
40+
keyPair: any,
41+
verificationMethod: string,
42+
) => {
43+
if (!credential) {
44+
throw new Error('A credential needs to be provided')
45+
}
46+
47+
return async (_opts: {
48+
credentialRequest: CredentialRequest
49+
credential: CredentialIssuanceInput
50+
format?: string
51+
jwtVerifyResult: any // Adjust type if necessary
52+
}): Promise<W3CVerifiableCredential | CompactSdJwtVc> => {
53+
const documentLoader = securityLoader().build()
54+
const verificationKey: any = Array.from(keyPair.values())[0]
55+
const keys = await Ed25519VerificationKey2020.from({ ...verificationKey })
56+
const suite = new Ed25519Signature2020({ key: keys })
57+
suite.verificationMethod = verificationMethod
58+
return await vc.issue({ credential, suite, documentLoader })
59+
}
60+
}
61+
3662
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3763
export const verifyCredential = async (credential: W3CVerifiableCredential, keyPair: any, verificationMethod: string): Promise<any> => {
3864
const documentLoader = securityLoader().build()

packages/callback-example/lib/__tests__/issuerCallback.spec.ts

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import { CredentialRequestClient, CredentialRequestClientBuilder, ProofOfPossess
44
import {
55
Alg,
66
CNonceState,
7-
CredentialSupported,
7+
CredentialConfigurationSupportedV1_0_13,
8+
CredentialIssuerMetadataV1_0_13,
9+
CredentialRequest,
810
IssuerCredentialSubjectDisplay,
911
IssueStatus,
1012
Jwt,
@@ -13,17 +15,18 @@ import {
1315
ProofOfPossession,
1416
} from '@sphereon/oid4vci-common'
1517
import { CredentialOfferSession } from '@sphereon/oid4vci-common/dist'
16-
import { CredentialSupportedBuilderV1_11, VcIssuer, VcIssuerBuilder } from '@sphereon/oid4vci-issuer'
18+
import { CredentialSupportedBuilderV1_13, VcIssuer, VcIssuerBuilder } from '@sphereon/oid4vci-issuer'
1719
import { MemoryStates } from '@sphereon/oid4vci-issuer'
1820
import { CredentialDataSupplierResult } from '@sphereon/oid4vci-issuer/dist/types'
1921
import { ICredential, IProofPurpose, IProofType, W3CVerifiableCredential } from '@sphereon/ssi-types'
2022
import { DIDDocument } from 'did-resolver'
2123
import * as jose from 'jose'
24+
import { v4 } from 'uuid'
2225

23-
import { generateDid, getIssuerCallback, verifyCredential } from '../IssuerCallback'
26+
import { generateDid, getIssuerCallbackV1_0_11, getIssuerCallbackV1_0_13, verifyCredential } from '../IssuerCallback'
2427

2528
const INITIATION_TEST_URI =
26-
'openid-initiate-issuance://?credential_type=OpenBadgeCredential&issuer=https%3A%2F%2Fjff%2Ewalt%2Eid%2Fissuer-api%2Foidc%2F&pre-authorized_code=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhOTUyZjUxNi1jYWVmLTQ4YjMtODIxYy00OTRkYzgyNjljZjAiLCJwcmUtYXV0aG9yaXplZCI6dHJ1ZX0.YE5DlalcLC2ChGEg47CQDaN1gTxbaQqSclIVqsSAUHE&user_pin_required=false'
29+
'openid-credential-offer://?credential_offer=%7B%22credential_issuer%22:%22https://credential-issuer.example.com%22,%22credential_configuration_ids%22:%5B%22UniversityDegreeCredential%22%5D,%22grants%22:%7B%22urn:ietf:params:oauth:grant-type:pre-authorized_code%22:%7B%22pre-authorized_code%22:%22oaKazRN8I0IbtZ0C7JuMn5%22,%22tx_code%22:%7B%22input_mode%22:%22text%22,%22description%22:%22Please%20enter%20the%20serial%20number%20of%20your%20physical%20drivers%20license%22%7D%7D%7D%7D'
2730
const IDENTIPROOF_ISSUER_URL = 'https://example.com/credential'
2831
const kid = 'did:example:ebfeb1f712ebc6f1c276e12ec21#keys-1'
2932
let keypair: KeyPair // Proof of Possession JWT
@@ -37,7 +40,7 @@ async function proofOfPossessionCallbackFunction(args: Jwt, kid?: string): Promi
3740
}
3841
return await new jose.SignJWT({ ...args.payload })
3942
.setProtectedHeader({ ...args.header })
40-
.setIssuedAt(args.payload.iat ?? Math.round(+new Date()/1000))
43+
.setIssuedAt(args.payload.iat ?? Math.round(+new Date() / 1000))
4144
.setIssuer(kid)
4245
.setAudience(args.payload.aud)
4346
.setExpirationTime('2h')
@@ -85,12 +88,14 @@ describe('issuerCallback', () => {
8588
const clientId = 'sphereon:wallet'
8689

8790
beforeAll(async () => {
88-
const credentialsSupported: CredentialSupported = new CredentialSupportedBuilderV1_11()
89-
.withCryptographicSuitesSupported('ES256K')
91+
const credentialsSupported: Record<string, CredentialConfigurationSupportedV1_0_13> = new CredentialSupportedBuilderV1_13()
92+
.withCredentialSigningAlgValuesSupported('ES256K')
9093
.withCryptographicBindingMethod('did')
9194
.withFormat('jwt_vc_json')
92-
.withTypes('VerifiableCredential')
93-
.withId('UniversityDegree_JWT')
95+
.withCredentialName('UniversityDegree_JWT')
96+
.withCredentialDefinition({
97+
type: ['VerifiableCredential', 'UniversityDegree_JWT'],
98+
})
9499
.withCredentialSupportedDisplay({
95100
name: 'University Credential',
96101
locale: 'en-US',
@@ -113,6 +118,7 @@ describe('issuerCallback', () => {
113118
createdAt: +new Date(),
114119
lastUpdatedAt: +new Date(),
115120
status: IssueStatus.OFFER_CREATED,
121+
notification_id: v4(),
116122
userPin: '123456',
117123
credentialOffer: {
118124
credential_offer: {
@@ -141,14 +147,14 @@ describe('issuerCallback', () => {
141147
const nonces = new MemoryStates<CNonceState>()
142148
await nonces.set('test_value', { cNonce: 'test_value', createdAt: +new Date(), issuerState: 'existing-state' })
143149
vcIssuer = new VcIssuerBuilder<DIDDocument>()
144-
.withAuthorizationServer('https://authorization-server')
150+
.withAuthorizationServers('https://authorization-server')
145151
.withCredentialEndpoint('https://credential-endpoint')
146152
.withCredentialIssuer(IDENTIPROOF_ISSUER_URL)
147153
.withIssuerDisplay({
148154
name: 'example issuer',
149155
locale: 'en-US',
150156
})
151-
.withCredentialsSupported(credentialsSupported)
157+
.withCredentialConfigurationsSupported(credentialsSupported)
152158
.withCredentialOfferStateManager(stateManager)
153159
.withCNonceStateManager(nonces)
154160
.withJWTVerifyCallback(verifyCallbackFunction)
@@ -192,7 +198,7 @@ describe('issuerCallback', () => {
192198
credentialSubject: {},
193199
issuanceDate: new Date().toISOString(),
194200
}
195-
const vc = await getIssuerCallback(credential, didKey.keyPairs, didKey.didDocument.verificationMethod[0].id)({})
201+
const vc = await getIssuerCallbackV1_0_11(credential, didKey.keyPairs, didKey.didDocument.verificationMethod[0].id)({})
196202
expect(vc).toEqual({
197203
'@context': ['https://www.w3.org/2018/credentials/v1', 'https://w3id.org/security/suites/ed25519-2020/v1'],
198204
credentialSubject: {},
@@ -211,11 +217,15 @@ describe('issuerCallback', () => {
211217
expect.objectContaining({ verified: true }),
212218
)
213219
})
220+
214221
it('Should pass requesting a verifiable credential using the client', async () => {
215222
const credReqClient = (await CredentialRequestClientBuilder.fromURI({ uri: INITIATION_TEST_URI }))
216223
.withCredentialEndpoint('https://oidc4vci.demo.spruceid.com/credential')
224+
.withCredentialEndpointFromMetadata({
225+
credential_configurations_supported: { VeriCred: { format: 'jwt_vc_json' } },
226+
} as unknown as CredentialIssuerMetadataV1_0_13)
217227
.withFormat('jwt_vc_json')
218-
.withCredentialType('credentialType')
228+
.withCredentialIdentifier('VeriCred')
219229
.withToken('token')
220230

221231
const jwt: Jwt = {
@@ -236,37 +246,39 @@ describe('issuerCallback', () => {
236246
callbacks: {
237247
signCallback: proofOfPossessionCallbackFunction,
238248
},
239-
version: OpenId4VCIVersion.VER_1_0_11,
249+
version: OpenId4VCIVersion.VER_1_0_13,
240250
})
241251
.withClientId(clientId)
242252
.withKid(kid)
243253
.build()
244254

245255
const credentialRequestClient = new CredentialRequestClient(credReqClient)
246-
const credentialRequest = await credentialRequestClient.createCredentialRequest({
247-
credentialTypes: ['VerifiableCredential'],
248-
format: 'jwt_vc_json',
256+
const credentialRequest: CredentialRequest = await credentialRequestClient.createCredentialRequest({
257+
credentialIdentifier: 'VerifiableCredential',
258+
// format: 'jwt_vc_json',
249259
proofInput: proof,
250-
version: OpenId4VCIVersion.VER_1_0_11,
260+
version: OpenId4VCIVersion.VER_1_0_13,
251261
})
262+
252263
expect(credentialRequest).toEqual({
253-
format: 'jwt_vc_json',
264+
// format: 'jwt_vc_json',
254265
proof: {
255266
jwt: expect.stringContaining('eyJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDpleGFtcGxlOmViZmViMWY3MTJlYmM2ZjFj'),
256267
proof_type: 'jwt',
257268
},
258-
types: ['VerifiableCredential'],
269+
credential_identifier: 'VerifiableCredential',
259270
})
260271

261272
const credentialResponse = await vcIssuer.issueCredential({
262273
credentialRequest: credentialRequest,
263274
credential,
264275
responseCNonce: state,
265-
credentialSignerCallback: getIssuerCallback(credential, didKey.keyPairs, didKey.didDocument.verificationMethod[0].id),
276+
credentialSignerCallback: getIssuerCallbackV1_0_13(credential, credentialRequest, didKey.keyPairs, didKey.didDocument.verificationMethod[0].id),
266277
})
267278

268279
expect(credentialResponse).toEqual({
269280
c_nonce: expect.any(String),
281+
notification_id: expect.any(String),
270282
c_nonce_expires_in: 300,
271283
credential: {
272284
'@context': ['https://www.w3.org/2018/credentials/v1', 'https://w3id.org/security/suites/ed25519-2020/v1'],
@@ -284,7 +296,7 @@ describe('issuerCallback', () => {
284296
},
285297
type: ['VerifiableCredential'],
286298
},
287-
format: 'jwt_vc_json',
299+
// format: 'jwt_vc_json',
288300
})
289301

290302
await expect(
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { getIssuerCallback, generateDid, verifyCredential } from './IssuerCallback'
1+
export { getIssuerCallbackV1_0_11, generateDid, verifyCredential } from './IssuerCallback'

packages/callback-example/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sphereon/oid4vci-callback-example",
3-
"version": "0.10.3",
3+
"version": "0.11.0",
44
"description": "OpenID 4 Verifiable Credential Issuance issuer callback example",
55
"source": "lib/index.ts",
66
"main": "dist/index.js",

packages/client/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ Release with support for the pre-authorized code flow only!
166166
- Documentation updates/fixes
167167

168168
- Fixes:
169-
- The acquireCredential in the OpenID4VCIClient was not using the access token, resulting in auth issues.
169+
- The acquireCredential in the OpenID4VCIClientV1_0_13 was not using the access token, resulting in auth issues.
170170

171171
## v0.3.1 - 2022-11-20
172172

packages/client/README.md

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ This initiates the client using a URI obtained from the Issuer using a link (URL
5252
already fetching the Server Metadata
5353

5454
```typescript
55-
import { OpenID4VCIClient } from '@sphereon/oid4vci-client';
55+
import { OpenID4VCIClientV1_0_13 } from '@sphereon/oid4vci-client';
5656

5757
// The client is initiated from a URI. This URI is provided by the Issuer, typically as a URL or QR code.
58-
const client = await OpenID4VCIClient.fromURI({
58+
const client = await OpenID4VCIClientV1_0_13.fromURI({
5959
uri: 'openid-initiate-issuance://?issuer=https%3A%2F%2Fissuer.research.identiproof.io&credential_type=OpenBadgeCredentialUrl&pre-authorized_code=4jLs9xZHEfqcoow0kHE7d1a8hUk6Sy-5bVSV2MqBUGUgiFFQi-ImL62T-FmLIo8hKA1UdMPH0lM1xAgcFkJfxIw9L-lI3mVs0hRT8YVwsEM1ma6N3wzuCdwtMU4bcwKp&user_pin_required=true',
6060
kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21#key-1', // Our DID. You can defer this also to when the acquireCredential method is called
6161
alg: Alg.ES256, // The signing Algorithm we will use. You can defer this also to when the acquireCredential method is called
@@ -68,6 +68,25 @@ console.log(client.getCredentialEndpoint()); // https://issuer.research.identipr
6868
console.log(client.getAccessTokenEndpoint()); // https://auth.research.identiproof.io/oauth2/token
6969
```
7070

71+
Using https scheme
72+
73+
```typescript
74+
import { OpenID4VCIClientV1_0_13 } from '@sphereon/oid4vci-client';
75+
76+
// The client is initiated from a URI. This URI is provided by the Issuer, typically as a URL or QR code.
77+
const client = await OpenID4VCIClientV1_0_13.fromURI({
78+
uri: 'https://launchpad.vii.electron.mattrlabs.io?credential_offer=%7B%22credential_issuer%22%3A%22https%3A%2F%2Flaunchpad.vii.electron.mattrlabs.io%22%2C%22credentials%22%3A%5B%7B%22format%22%3A%22ldp_vc%22%2C%22types%22%3A%5B%22OpenBadgeCredential%22%5D%7D%5D%2C%22grants%22%3A%7B%22urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Apre-authorized_code%22%3A%7B%22pre-authorized_code%22%3A%22UPZohaodPlLBnGsqB02n2tIupCIg8nKRRUEUHWA665X%22%7D%7D%7D',
79+
kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21#key-1', // Our DID. You can defer this also to when the acquireCredential method is called
80+
alg: Alg.ES256, // The signing Algorithm we will use. You can defer this also to when the acquireCredential method is called
81+
clientId: 'test-clientId', // The clientId if the Authrozation Service requires it. If a clientId is needed you can defer this also to when the acquireAccessToken method is called
82+
retrieveServerMetadata: true, // Already retrieve the server metadata. Can also be done afterwards by invoking a method yourself.
83+
});
84+
85+
console.log(client.getIssuer()); // https://launchpad.vii.electron.mattrlabs.io
86+
console.log(client.getCredentialEndpoint()); // https://launchpad.vii.electron.mattrlabs.io/credential
87+
console.log(client.getAccessTokenEndpoint()); // https://launchpad.vii.electron.mattrlabs.io/oauth2/token
88+
```
89+
7190
## Server metadata
7291

7392
The OID4VCI Server metadata contains information about token endpoints, credential endpoints, as well as additional
@@ -187,15 +206,15 @@ The OpenID4VCI spec defines a server metadata object that contains information a
187206
support. Next to this predefined endpoint there are also the well-known locations for OpenID Connect Discovery
188207
configuration and
189208
Oauth2 Authorization Server configuration. These contain for instance the token endpoints.
190-
The MetadataClient checks the OpenID4VCI well-known location for the medata and existence of a token endpoint. If the
209+
The MetadataClientV1_0_13 checks the OpenID4VCI well-known location for the medata and existence of a token endpoint. If the
191210
OpenID4VCI well-known location is not found, the OIDC/OAuth2 well-known locations will be tried:
192211

193212
Example:
194213

195214
```typescript
196-
import { MetadataClient } from '@sphereon/oid4vci-client';
215+
import { MetadataClientV1_0_13 } from '@sphereon/oid4vci-client';
197216

198-
const metadata = await MetadataClient.retrieveAllMetadataFromCredentialOffer(initiationRequestWithUrl);
217+
const metadata = await MetadataClientV1_0_13.retrieveAllMetadataFromCredentialOffer(initiationRequestWithUrl);
199218

200219
console.log(metadata);
201220
/**

0 commit comments

Comments
 (0)