@sphereon/ssi-sdk.oid4vci-holder 0.34.1-feature.SSISDK.26.RP.58 → 0.34.1-feature.SSISDK.44.finish.dcql.310

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sphereon/ssi-sdk.oid4vci-holder",
3
- "version": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
3
+ "version": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
4
4
  "source": "src/index.ts",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -26,40 +26,41 @@
26
26
  "build": "tsup --config ../../tsup.config.ts --tsconfig ../../tsconfig.tsup.json"
27
27
  },
28
28
  "dependencies": {
29
- "@sphereon/did-auth-siop": "0.19.1-feature.SSISDK.13.32",
29
+ "@sphereon/did-auth-siop": "0.19.1-next.220",
30
30
  "@sphereon/kmp-mdoc-core": "0.2.0-SNAPSHOT.26",
31
- "@sphereon/oid4vci-client": "0.19.1-feature.SSISDK.13.32",
32
- "@sphereon/oid4vci-common": "0.19.1-feature.SSISDK.13.32",
33
- "@sphereon/ssi-sdk-ext.did-utils": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
34
- "@sphereon/ssi-sdk-ext.identifier-resolution": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
35
- "@sphereon/ssi-sdk-ext.jwt-service": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
36
- "@sphereon/ssi-sdk-ext.key-utils": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
37
- "@sphereon/ssi-sdk.contact-manager": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
38
- "@sphereon/ssi-sdk.core": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
39
- "@sphereon/ssi-sdk.credential-store": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
40
- "@sphereon/ssi-sdk.credential-validation": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
41
- "@sphereon/ssi-sdk.data-store": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
42
- "@sphereon/ssi-sdk.issuance-branding": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
43
- "@sphereon/ssi-sdk.mdl-mdoc": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
44
- "@sphereon/ssi-sdk.oidf-client": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
45
- "@sphereon/ssi-sdk.sd-jwt": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
46
- "@sphereon/ssi-sdk.siopv2-oid4vp-common": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
47
- "@sphereon/ssi-sdk.siopv2-oid4vp-op-auth": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
48
- "@sphereon/ssi-sdk.xstate-machine-persistence": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
49
- "@sphereon/ssi-types": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
31
+ "@sphereon/oid4vci-client": "0.19.1-next.220",
32
+ "@sphereon/oid4vci-common": "0.19.1-next.220",
33
+ "@sphereon/ssi-sdk-ext.did-utils": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
34
+ "@sphereon/ssi-sdk-ext.identifier-resolution": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
35
+ "@sphereon/ssi-sdk-ext.jwt-service": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
36
+ "@sphereon/ssi-sdk-ext.key-utils": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
37
+ "@sphereon/ssi-sdk.contact-manager": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
38
+ "@sphereon/ssi-sdk.core": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
39
+ "@sphereon/ssi-sdk.credential-store": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
40
+ "@sphereon/ssi-sdk.credential-validation": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
41
+ "@sphereon/ssi-sdk.data-store-types": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
42
+ "@sphereon/ssi-sdk.issuance-branding": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
43
+ "@sphereon/ssi-sdk.mdl-mdoc": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
44
+ "@sphereon/ssi-sdk.oidf-client": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
45
+ "@sphereon/ssi-sdk.sd-jwt": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
46
+ "@sphereon/ssi-sdk.siopv2-oid4vp-common": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
47
+ "@sphereon/ssi-sdk.siopv2-oid4vp-op-auth": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
48
+ "@sphereon/ssi-sdk.xstate-machine-persistence": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
49
+ "@sphereon/ssi-types": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
50
50
  "@veramo/core": "4.2.0",
51
51
  "@veramo/data-store": "4.2.0",
52
52
  "@veramo/utils": "4.2.0",
53
53
  "ajv": "^8.17.1",
54
54
  "ajv-formats": "^3.0.1",
55
+ "dcql": "1.0.1",
55
56
  "i18n-js": "^3.9.2",
56
57
  "lodash.memoize": "^4.1.2",
57
58
  "uuid": "^9.0.1",
58
59
  "xstate": "^4.38.3"
59
60
  },
60
61
  "devDependencies": {
61
- "@sphereon/oid4vc-common": "0.19.1-feature.SSISDK.13.32",
62
- "@sphereon/ssi-sdk-ext.did-resolver-jwk": "0.34.1-feature.SSISDK.26.RP.58+9389054b",
62
+ "@sphereon/oid4vc-common": "0.19.1-next.220",
63
+ "@sphereon/ssi-sdk-ext.did-resolver-jwk": "0.34.1-feature.SSISDK.44.finish.dcql.310+ea750f36",
63
64
  "@sphereon/ssi-sdk.siopv2-oid4vp-common": "workspace:*",
64
65
  "@types/i18n-js": "^3.8.9",
65
66
  "@types/lodash.memoize": "^4.1.9",
@@ -89,5 +90,5 @@
89
90
  "OID4VCI",
90
91
  "State Machine"
91
92
  ],
92
- "gitHead": "9389054b1da3dda085e28b2ec27063e20cc296c6"
93
+ "gitHead": "ea750f3627f38e49a3527f5826d3e09b9dcdab14"
93
94
  }
@@ -1,4 +1,4 @@
1
- import { CredentialOfferClient, MetadataClient, OpenID4VCIClient } from '@sphereon/oid4vci-client'
1
+ import { CredentialOfferClient, MetadataClient, OpenID4VCIClient, OpenID4VCIClientV1_0_15 } from '@sphereon/oid4vci-client'
2
2
  import {
3
3
  AuthorizationDetails,
4
4
  AuthorizationRequestOpts,
@@ -9,8 +9,6 @@ import {
9
9
  CredentialOfferRequestWithBaseUrl,
10
10
  DefaultURISchemes,
11
11
  EndpointMetadataResult,
12
- getTypesFromAuthorizationDetails,
13
- getTypesFromCredentialOffer,
14
12
  getTypesFromObject,
15
13
  Jwt,
16
14
  NotificationRequest,
@@ -35,7 +33,6 @@ import {
35
33
  ConnectionType,
36
34
  CorrelationIdentifierType,
37
35
  CredentialCorrelationType,
38
- CredentialRole,
39
36
  ensureRawDocument,
40
37
  FindPartyArgs,
41
38
  IBasicCredentialLocaleBranding,
@@ -45,17 +42,17 @@ import {
45
42
  IIssuerLocaleBranding,
46
43
  NonPersistedIdentity,
47
44
  Party,
48
- } from '@sphereon/ssi-sdk.data-store'
45
+ } from '@sphereon/ssi-sdk.data-store-types'
49
46
  import {
50
47
  CredentialMapper,
51
48
  type CredentialProofFormat,
49
+ CredentialRole,
52
50
  HasherSync,
53
51
  IVerifiableCredential,
54
52
  JoseSignatureAlgorithm,
55
53
  JoseSignatureAlgorithmString,
56
54
  JwtDecodedVerifiableCredential,
57
55
  Loggers,
58
- OriginalVerifiableCredential,
59
56
  parseDid,
60
57
  SdJwtDecodedVerifiableCredentialPayload,
61
58
  WrappedW3CVerifiableCredential,
@@ -71,10 +68,12 @@ import {
71
68
  W3CVerifiableCredential,
72
69
  } from '@veramo/core'
73
70
  import { asArray, computeEntryHash } from '@veramo/utils'
71
+ import fetch from 'cross-fetch'
74
72
  import { decodeJWT } from 'did-jwt'
75
73
  import { v4 as uuidv4 } from 'uuid'
76
74
  import { OID4VCIMachine } from '../machines/oid4vciMachine'
77
75
  import {
76
+ extractCredentialFromResponse,
78
77
  getBasicIssuerLocaleBranding,
79
78
  getCredentialBranding,
80
79
  getCredentialConfigsSupportedMerged,
@@ -85,7 +84,6 @@ import {
85
84
  startFirstPartApplicationMachine,
86
85
  verifyCredentialToAccept,
87
86
  } from '../services/OID4VCIHolderService'
88
- import 'cross-fetch/polyfill'
89
87
  import {
90
88
  AddContactIdentityArgs,
91
89
  AssertValidCredentialsArgs,
@@ -111,6 +109,8 @@ import {
111
109
  OnContactIdentityCreatedArgs,
112
110
  OnCredentialStoredArgs,
113
111
  OnIdentifierCreatedArgs,
112
+ PrepareAuthorizationRequestArgs,
113
+ PrepareAuthorizationResult,
114
114
  PrepareStartArgs,
115
115
  RequestType,
116
116
  RequiredContext,
@@ -216,6 +216,7 @@ export class OID4VCIHolder implements IAgentPlugin {
216
216
  oid4vciHolderStart: this.oid4vciHolderStart.bind(this),
217
217
  oid4vciHolderGetIssuerMetadata: this.oid4vciHolderGetIssuerMetadata.bind(this),
218
218
  oid4vciHolderGetMachineInterpreter: this.oid4vciHolderGetMachineInterpreter.bind(this),
219
+ oid4vciHolderPrepareAuthorizationRequest: this.oid4vciHolderPrepareAuthorizationRequest.bind(this),
219
220
  oid4vciHolderCreateCredentialsToSelectFrom: this.oid4vciHolderCreateCredentialsToSelectFrom.bind(this),
220
221
  oid4vciHolderGetContact: this.oid4vciHolderGetContact.bind(this),
221
222
  oid4vciHolderGetCredentials: this.oid4vciHolderGetCredentials.bind(this),
@@ -229,7 +230,7 @@ export class OID4VCIHolder implements IAgentPlugin {
229
230
  oid4vciHolderStoreIssuerBranding: this.oid4vciHolderStoreIssuerBranding.bind(this),
230
231
  }
231
232
 
232
- private readonly vcFormatPreferences: Array<string> = ['dc+sd-jwt', 'vc+sd-jwt', 'mso_mdoc', 'jwt_vc_json', 'jwt_vc', 'ldp_vc']
233
+ private readonly vcFormatPreferences: Array<string> = ['dc+sd-jwt', 'vc+sd-jwt', 'mso_mdoc', 'jwt_vc_json', 'jwt_vc', 'ldp_vc'] // TODO see SSISDK-52 concerning vc+sd-jwt
233
234
  private readonly jsonldCryptographicSuitePreferences: Array<string> = [
234
235
  'Ed25519Signature2018',
235
236
  'EcdsaSecp256k1Signature2019',
@@ -326,6 +327,8 @@ export class OID4VCIHolder implements IAgentPlugin {
326
327
  startFirstPartApplicationMachine({ ...args, stateNavigationListener: opts.firstPartyStateNavigationListener }, context),
327
328
  [OID4VCIMachineServices.createCredentialsToSelectFrom]: (args: CreateCredentialsToSelectFromArgs) =>
328
329
  this.oid4vciHolderCreateCredentialsToSelectFrom(args, context),
330
+ [OID4VCIMachineServices.prepareAuthorizationRequest]: (args: PrepareAuthorizationRequestArgs) =>
331
+ this.oid4vciHolderPrepareAuthorizationRequest(args, context),
329
332
  [OID4VCIMachineServices.getContact]: (args: GetContactArgs) => this.oid4vciHolderGetContact(args, context),
330
333
  [OID4VCIMachineServices.getCredentials]: (args: GetCredentialsArgs) =>
331
334
  this.oid4vciHolderGetCredentials({ accessTokenOpts: args.accessTokenOpts ?? opts.accessTokenOpts, ...args }, context),
@@ -399,11 +402,10 @@ export class OID4VCIHolder implements IAgentPlugin {
399
402
  if (authFormats && authFormats.length > 0) {
400
403
  formats = Array.from(new Set(authFormats))
401
404
  }
402
- let oid4vciClient: OpenID4VCIClient
403
- let types: string[][] | undefined = undefined
405
+ let oid4vciClient: OpenID4VCIClientV1_0_15
404
406
  let offer: CredentialOfferRequestWithBaseUrl | undefined
405
407
  if (requestData.existingClientState) {
406
- oid4vciClient = await OpenID4VCIClient.fromState({ state: requestData.existingClientState })
408
+ oid4vciClient = await OpenID4VCIClientV1_0_15.fromState({ state: requestData.existingClientState })
407
409
  offer = oid4vciClient.credentialOffer
408
410
  } else {
409
411
  offer = requestData.credentialOffer
@@ -425,46 +427,44 @@ export class OID4VCIHolder implements IAgentPlugin {
425
427
  if (!offer) {
426
428
  // else no offer, meaning we have an issuer URL
427
429
  logger.log(`Issuer url received (no credential offer): ${uri}`)
428
- oid4vciClient = await OpenID4VCIClient.fromCredentialIssuer({
430
+ oid4vciClient = await OpenID4VCIClientV1_0_15.fromCredentialIssuer({
429
431
  credentialIssuer: uri,
430
432
  authorizationRequest: authorizationRequestOpts,
431
433
  clientId: authorizationRequestOpts.clientId,
432
- createAuthorizationRequestURL: requestData.createAuthorizationRequestURL ?? true,
434
+ createAuthorizationRequestURL: false, // requestData.createAuthorizationRequestURL ?? true,
433
435
  })
434
436
  } else {
435
437
  logger.log(`Credential offer received: ${uri}`)
436
- oid4vciClient = await OpenID4VCIClient.fromURI({
438
+ oid4vciClient = await OpenID4VCIClientV1_0_15.fromURI({
437
439
  uri,
438
440
  authorizationRequest: authorizationRequestOpts,
439
441
  clientId: authorizationRequestOpts.clientId,
440
- createAuthorizationRequestURL: requestData.createAuthorizationRequestURL ?? true,
442
+ createAuthorizationRequestURL: false, // requestData.createAuthorizationRequestURL ?? true,
441
443
  })
442
444
  }
443
445
  }
444
446
 
447
+ let configurationIds: Array<string> = []
445
448
  if (offer) {
446
- types = getTypesFromCredentialOffer(offer.original_credential_offer)
449
+ configurationIds = offer.original_credential_offer.credential_configuration_ids
447
450
  } else {
448
- types = asArray(authorizationRequestOpts.authorizationDetails)
449
- .map((authReqOpts) => getTypesFromAuthorizationDetails(authReqOpts) ?? [])
450
- .filter((inner) => inner.length > 0)
451
+ configurationIds = asArray(authorizationRequestOpts.authorizationDetails)
452
+ .filter((authDetails): authDetails is Exclude<AuthorizationDetails, string> => typeof authDetails !== 'string')
453
+ .map((authReqOpts) => authReqOpts.credential_configuration_id)
454
+ .filter((id): id is string => !!id)
451
455
  }
452
456
 
453
- const serverMetadata = await oid4vciClient.retrieveServerMetadata()
454
457
  const credentialsSupported = await getCredentialConfigsSupportedMerged({
455
458
  client: oid4vciClient,
456
459
  vcFormatPreferences: formats,
457
- types,
460
+ configurationIds,
458
461
  })
462
+
463
+ const serverMetadata = await oid4vciClient.retrieveServerMetadata()
459
464
  const credentialBranding = await getCredentialBranding({ credentialsSupported, context })
460
- const authorizationCodeURL = oid4vciClient.authorizationURL
461
- if (authorizationCodeURL) {
462
- logger.log(`authorization code URL ${authorizationCodeURL}`)
463
- }
464
465
  const oid4vciClientState = JSON.parse(await oid4vciClient.exportState())
465
466
 
466
467
  return {
467
- authorizationCodeURL,
468
468
  credentialBranding,
469
469
  credentialsSupported,
470
470
  serverMetadata,
@@ -472,6 +472,42 @@ export class OID4VCIHolder implements IAgentPlugin {
472
472
  }
473
473
  }
474
474
 
475
+ private async oid4vciHolderPrepareAuthorizationRequest(
476
+ args: PrepareAuthorizationRequestArgs,
477
+ context: RequiredContext,
478
+ ): Promise<PrepareAuthorizationResult> {
479
+ const { openID4VCIClientState, contact } = args
480
+ if (!openID4VCIClientState) {
481
+ return Promise.reject(Error('Missing openID4VCI client state in context'))
482
+ }
483
+
484
+ const clientId = contact?.identities
485
+ .map((identity) => {
486
+ const connectionConfig = identity.connection?.config
487
+ if (connectionConfig && 'clientId' in connectionConfig) {
488
+ return connectionConfig.clientId
489
+ }
490
+ return undefined
491
+ })
492
+ .find((clientId) => clientId)
493
+
494
+ if (!clientId) {
495
+ return Promise.reject(Error(`Missing client id in contact's connectionConfig`))
496
+ }
497
+ const client = await OpenID4VCIClient.fromState({ state: openID4VCIClientState })
498
+ const authorizationCodeURL = await client.createAuthorizationRequestUrl({
499
+ authorizationRequest: {
500
+ clientId: clientId,
501
+ } satisfies AuthorizationRequestOpts,
502
+ })
503
+ if (authorizationCodeURL) {
504
+ logger.log(`authorization code URL ${authorizationCodeURL}`)
505
+ }
506
+ return {
507
+ authorizationCodeURL,
508
+ }
509
+ }
510
+
475
511
  private async oid4vciHolderCreateCredentialsToSelectFrom(
476
512
  args: CreateCredentialsToSelectFromArgs,
477
513
  context: RequiredContext,
@@ -587,7 +623,7 @@ export class OID4VCIHolder implements IAgentPlugin {
587
623
  return Promise.reject(Error('Missing openID4VCI client state in context'))
588
624
  }
589
625
 
590
- const client = await OpenID4VCIClient.fromState({ state: openID4VCIClientState })
626
+ const client = await OpenID4VCIClientV1_0_15.fromState({ state: openID4VCIClientState })
591
627
  const credentialsSupported = await getCredentialConfigsSupportedMerged({
592
628
  client,
593
629
  vcFormatPreferences: this.vcFormatPreferences,
@@ -939,21 +975,8 @@ export class OID4VCIHolder implements IAgentPlugin {
939
975
  ? 'credential_accepted_holder_signed'
940
976
  : 'credential_deleted_holder_signed'
941
977
  logger.log(`Subject issuance/signing will be used, with event`, event)
942
- const credentialResponse = mappedCredentialToAccept.credentialToAccept.credentialResponse
943
- let issuerVC
944
- if ('credential' in credentialResponse) {
945
- issuerVC = credentialResponse.credential as OriginalVerifiableCredential
946
- } else if (
947
- 'credentials' in credentialResponse &&
948
- credentialResponse.credentials &&
949
- Array.isArray(credentialResponse.credentials) &&
950
- credentialResponse.credentials.length > 0
951
- ) {
952
- issuerVC = credentialResponse.credentials[0].credential as OriginalVerifiableCredential // FIXME SSISDK-13 (no multi-credential support yet)
953
- }
954
- if (!issuerVC) {
955
- return Promise.reject(Error('No credential found in credential response'))
956
- }
978
+
979
+ const issuerVC = extractCredentialFromResponse(mappedCredentialToAccept.credentialToAccept.credentialResponse)
957
980
  const wrappedIssuerVC = CredentialMapper.toWrappedVerifiableCredential(issuerVC, { hasher: this.hasher ?? defaultHasher })
958
981
  console.log(`Wrapped VC: ${wrappedIssuerVC.type}, ${wrappedIssuerVC.format}`)
959
982
  // We will use the subject of the VCI Issuer (the holder, as the issuer of the new credential, so the below is not a mistake!)
@@ -1,6 +1,6 @@
1
1
  import { assign, createMachine, DoneInvokeEvent, interpret } from 'xstate'
2
2
  import { AuthorizationChallengeCodeResponse, AuthorizationChallengeError, AuthorizationChallengeErrorResponse } from '@sphereon/oid4vci-common'
3
- import { DidAuthConfig } from '@sphereon/ssi-sdk.data-store'
3
+ import { DidAuthConfig } from '@sphereon/ssi-sdk.data-store-types'
4
4
  import { CreateConfigResult } from '@sphereon/ssi-sdk.siopv2-oid4vp-op-auth'
5
5
  import { createConfig, getSiopRequest, sendAuthorizationChallengeRequest, sendAuthorizationResponse } from '../services/FirstPartyMachineServices'
6
6
  import { translate } from '../localization/Localization'
@@ -1,5 +1,5 @@
1
1
  import { AuthorizationChallengeCodeResponse, AuthzFlowType, toAuthorizationResponsePayload } from '@sphereon/oid4vci-common'
2
- import { IBasicIssuerLocaleBranding, Identity, IIssuerLocaleBranding, Party } from '@sphereon/ssi-sdk.data-store'
2
+ import { IBasicIssuerLocaleBranding, Identity, IIssuerLocaleBranding, Party } from '@sphereon/ssi-sdk.data-store-types'
3
3
  import { assign, createMachine, DoneInvokeEvent, interpret } from 'xstate'
4
4
  import { translate } from '../localization/Localization'
5
5
  import {
@@ -28,6 +28,7 @@ import {
28
28
  SelectCredentialsEvent,
29
29
  SetAuthorizationCodeURLEvent,
30
30
  VerificationCodeEvent,
31
+ PrepareAuthorizationResult,
31
32
  } from '../types/IOID4VCIHolder'
32
33
  import { FirstPartyMachineStateTypes } from '../types/FirstPartyMachine'
33
34
 
@@ -98,9 +99,7 @@ const oid4vciRequireAuthorizationGuard = (ctx: OID4VCIMachineContext, _event: OI
98
99
  throw Error('Missing openID4VCI client state in context')
99
100
  }
100
101
 
101
- if (!openID4VCIClientState.authorizationURL) {
102
- return false
103
- } else if (openID4VCIClientState.authorizationRequestOpts) {
102
+ if (openID4VCIClientState.authorizationURL && openID4VCIClientState.authorizationRequestOpts) {
104
103
  // We have authz options or there is not credential offer to begin with.
105
104
  // We require authz as long as we do not have the authz code response
106
105
  return !ctx.openID4VCIClientState?.authorizationCodeResponse
@@ -164,6 +163,9 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
164
163
  [OID4VCIMachineServices.start]: {
165
164
  data: StartResult
166
165
  }
166
+ [OID4VCIMachineServices.prepareAuthorizationRequest]: {
167
+ data: PrepareAuthorizationResult
168
+ }
167
169
  [OID4VCIMachineServices.createCredentialsToSelectFrom]: {
168
170
  data: Array<CredentialToSelectFromResult>
169
171
  }
@@ -208,7 +210,6 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
208
210
  onDone: {
209
211
  target: OID4VCIMachineStates.createCredentialsToSelectFrom,
210
212
  actions: assign({
211
- authorizationCodeURL: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<StartResult>) => _event.data.authorizationCodeURL,
212
213
  credentialBranding: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<StartResult>) => _event.data.credentialBranding ?? {},
213
214
  credentialsSupported: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<StartResult>) => _event.data.credentialsSupported,
214
215
  serverMetadata: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<StartResult>) => _event.data.serverMetadata,
@@ -439,6 +440,10 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
439
440
  target: OID4VCIMachineStates.startFirstPartApplicationFlow,
440
441
  cond: OID4VCIMachineGuards.isFirstPartyApplication,
441
442
  },
443
+ {
444
+ target: OID4VCIMachineStates.prepareAuthorizationRequest,
445
+ cond: OID4VCIMachineGuards.requireAuthorizationGuard,
446
+ },
442
447
  {
443
448
  target: OID4VCIMachineStates.initiateAuthorizationRequest,
444
449
  cond: OID4VCIMachineGuards.requireAuthorizationGuard,
@@ -511,12 +516,16 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
511
516
  target: OID4VCIMachineStates.startFirstPartApplicationFlow,
512
517
  cond: OID4VCIMachineGuards.isFirstPartyApplication,
513
518
  },
519
+ {
520
+ target: OID4VCIMachineStates.prepareAuthorizationRequest,
521
+ cond: OID4VCIMachineGuards.requireAuthorizationGuard,
522
+ },
514
523
  {
515
524
  target: OID4VCIMachineStates.verifyPin,
516
525
  cond: OID4VCIMachineGuards.requirePinGuard,
517
526
  },
518
527
  {
519
- target: OID4VCIMachineStates.initiateAuthorizationRequest,
528
+ target: OID4VCIMachineStates.prepareAuthorizationRequest,
520
529
  cond: OID4VCIMachineGuards.requireAuthorizationGuard,
521
530
  },
522
531
  {
@@ -524,6 +533,29 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
524
533
  },
525
534
  ],
526
535
  },
536
+ [OID4VCIMachineStates.prepareAuthorizationRequest]: {
537
+ id: OID4VCIMachineStates.prepareAuthorizationRequest,
538
+ invoke: {
539
+ src: OID4VCIMachineServices.prepareAuthorizationRequest,
540
+ onDone: {
541
+ target: OID4VCIMachineStates.initiateAuthorizationRequest,
542
+ actions: assign({
543
+ authorizationCodeURL: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<PrepareAuthorizationResult>) =>
544
+ _event.data.authorizationCodeURL,
545
+ }),
546
+ },
547
+ onError: {
548
+ target: OID4VCIMachineStates.handleError,
549
+ actions: assign({
550
+ error: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
551
+ title: translate('oid4vci_machine_prepare_authorization_error_title'),
552
+ message: _event.data.message,
553
+ stack: _event.data.stack,
554
+ }),
555
+ }),
556
+ },
557
+ },
558
+ },
527
559
  [OID4VCIMachineStates.initiateAuthorizationRequest]: {
528
560
  id: OID4VCIMachineStates.initiateAuthorizationRequest,
529
561
  on: {
@@ -1,5 +1,5 @@
1
1
  import { CredentialsSupportedDisplay, NameAndLocale } from '@sphereon/oid4vci-common'
2
- import { IBasicCredentialClaim, IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding } from '@sphereon/ssi-sdk.data-store'
2
+ import { IBasicCredentialClaim, IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding } from '@sphereon/ssi-sdk.data-store-types'
3
3
  import { SdJwtClaimDisplayMetadata, SdJwtClaimMetadata, SdJwtClaimPath, SdJwtTypeDisplayMetadata } from '@sphereon/ssi-types'
4
4
  import {
5
5
  IssuerLocaleBrandingFromArgs,
@@ -1,16 +1,15 @@
1
1
  import { LOG } from '@sphereon/oid4vci-client'
2
2
  import {
3
+ AuthorizationChallengeCodeResponse,
3
4
  CredentialConfigurationSupported,
4
- CredentialSupportedSdJwtVc,
5
5
  CredentialConfigurationSupportedSdJwtVcV1_0_15,
6
- CredentialOfferFormatV1_0_11,
7
6
  CredentialResponse,
7
+ CredentialResponseV1_0_15,
8
+ CredentialSupportedSdJwtVc,
8
9
  getSupportedCredentials,
9
10
  getTypesFromCredentialSupported,
10
11
  getTypesFromObject,
11
12
  MetadataDisplay,
12
- OpenId4VCIVersion,
13
- AuthorizationChallengeCodeResponse,
14
13
  } from '@sphereon/oid4vci-common'
15
14
  import { KeyUse } from '@sphereon/ssi-sdk-ext.did-resolver-jwk'
16
15
  import { getOrCreatePrimaryIdentifier, SupportedDidMethodEnum } from '@sphereon/ssi-sdk-ext.did-utils'
@@ -23,7 +22,8 @@ import {
23
22
  managedIdentifierToJwk,
24
23
  } from '@sphereon/ssi-sdk-ext.identifier-resolution'
25
24
  import { keyTypeFromCryptographicSuite } from '@sphereon/ssi-sdk-ext.key-utils'
26
- import { IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding } from '@sphereon/ssi-sdk.data-store'
25
+ import { defaultHasher } from '@sphereon/ssi-sdk.core'
26
+ import { IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding } from '@sphereon/ssi-sdk.data-store-types'
27
27
  import {
28
28
  CredentialMapper,
29
29
  Hasher,
@@ -40,8 +40,12 @@ import {
40
40
  } from '@sphereon/ssi-types'
41
41
  import { asArray } from '@veramo/utils'
42
42
  import { translate } from '../localization/Localization'
43
+ import { FirstPartyMachine } from '../machines/firstPartyMachine'
44
+ import { issuerLocaleBrandingFrom, oid4vciGetCredentialBrandingFrom, sdJwtGetCredentialBrandingFrom } from '../mappers/OIDC4VCIBrandingMapper'
45
+ import { FirstPartyMachineState, FirstPartyMachineStateTypes } from '../types/FirstPartyMachine'
43
46
  import {
44
47
  DidAgents,
48
+ GetBasicIssuerLocaleBrandingArgs,
45
49
  GetCredentialBrandingArgs,
46
50
  GetCredentialConfigsSupportedArgs,
47
51
  GetCredentialConfigsSupportedBySingleTypeOrIdArgs,
@@ -49,22 +53,17 @@ import {
49
53
  GetIssuanceCryptoSuiteArgs,
50
54
  GetIssuanceDidMethodArgs,
51
55
  GetIssuanceOptsArgs,
52
- GetBasicIssuerLocaleBrandingArgs,
53
56
  GetPreferredCredentialFormatsArgs,
54
57
  IssuanceOpts,
55
58
  MapCredentialToAcceptArgs,
56
59
  MappedCredentialToAccept,
57
60
  OID4VCIHolderEvent,
61
+ RequiredContext,
58
62
  SelectAppLocaleBrandingArgs,
63
+ StartFirstPartApplicationMachine,
59
64
  VerificationResult,
60
65
  VerifyCredentialToAcceptArgs,
61
- StartFirstPartApplicationMachine,
62
- RequiredContext,
63
66
  } from '../types/IOID4VCIHolder'
64
- import { oid4vciGetCredentialBrandingFrom, sdJwtGetCredentialBrandingFrom, issuerLocaleBrandingFrom } from '../mappers/OIDC4VCIBrandingMapper'
65
- import { FirstPartyMachine } from '../machines/firstPartyMachine'
66
- import { FirstPartyMachineState, FirstPartyMachineStateTypes } from '../types/FirstPartyMachine'
67
- import { defaultHasher } from '@sphereon/ssi-sdk.core'
68
67
 
69
68
  export const getCredentialBranding = async (args: GetCredentialBrandingArgs): Promise<Record<string, Array<IBasicCredentialLocaleBranding>>> => {
70
69
  const { credentialsSupported, context } = args
@@ -153,21 +152,7 @@ export const selectCredentialLocaleBranding = async (
153
152
  export const verifyCredentialToAccept = async (args: VerifyCredentialToAcceptArgs): Promise<VerificationResult> => {
154
153
  const { mappedCredential, hasher, onVerifyEBSICredentialIssuer, schemaValidation, context } = args
155
154
 
156
- const credentialResponse = mappedCredential.credentialToAccept.credentialResponse
157
- let credential
158
- if ('credential' in credentialResponse) {
159
- credential = credentialResponse.credential as OriginalVerifiableCredential
160
- } else if (
161
- 'credentials' in credentialResponse &&
162
- credentialResponse.credentials &&
163
- Array.isArray(credentialResponse.credentials) &&
164
- credentialResponse.credentials.length > 0
165
- ) {
166
- credential = credentialResponse.credentials[0].credential as OriginalVerifiableCredential // FIXME SSISDK-13 (no multi-credential support yet)
167
- }
168
- if (!credential) {
169
- return Promise.reject(Error('No credential found in credential response'))
170
- }
155
+ const credential = extractCredentialFromResponse(mappedCredential.credentialToAccept.credentialResponse)
171
156
 
172
157
  const wrappedVC = CredentialMapper.toWrappedVerifiableCredential(credential, { hasher: hasher ?? defaultHasher })
173
158
  if (
@@ -216,21 +201,7 @@ export const verifyCredentialToAccept = async (args: VerifyCredentialToAcceptArg
216
201
  export const mapCredentialToAccept = async (args: MapCredentialToAcceptArgs): Promise<MappedCredentialToAccept> => {
217
202
  const { credentialToAccept, hasher } = args
218
203
 
219
- const credentialResponse: CredentialResponse = credentialToAccept.credentialResponse
220
- let verifiableCredential: W3CVerifiableCredential | undefined
221
- if ('credential' in credentialResponse) {
222
- verifiableCredential = credentialResponse.credential
223
- } else if (
224
- 'credentials' in credentialResponse &&
225
- credentialResponse.credentials &&
226
- Array.isArray(credentialResponse.credentials) &&
227
- credentialResponse.credentials.length > 0
228
- ) {
229
- verifiableCredential = credentialResponse.credentials[0].credential // FIXME SSISDK-13 (no multi-credential support yet)
230
- }
231
- if (!verifiableCredential) {
232
- return Promise.reject(Error('No credential found in credential response'))
233
- }
204
+ const verifiableCredential = extractCredentialFromResponse(credentialToAccept.credentialResponse) as W3CVerifiableCredential
234
205
 
235
206
  const wrappedVerifiableCredential: WrappedVerifiableCredential = CredentialMapper.toWrappedVerifiableCredential(
236
207
  verifiableCredential as OriginalVerifiableCredential,
@@ -238,9 +209,7 @@ export const mapCredentialToAccept = async (args: MapCredentialToAcceptArgs): Pr
238
209
  )
239
210
  let uniformVerifiableCredential: IVerifiableCredential
240
211
  if (CredentialMapper.isSdJwtDecodedCredential(wrappedVerifiableCredential.credential)) {
241
- uniformVerifiableCredential = await sdJwtDecodedCredentialToUniformCredential(
242
- <SdJwtDecodedVerifiableCredential>wrappedVerifiableCredential.credential,
243
- )
212
+ uniformVerifiableCredential = sdJwtDecodedCredentialToUniformCredential(<SdJwtDecodedVerifiableCredential>wrappedVerifiableCredential.credential)
244
213
  } else if (CredentialMapper.isSdJwtEncoded(wrappedVerifiableCredential.credential)) {
245
214
  if (!hasher) {
246
215
  return Promise.reject('a hasher is required for encoded SD-JWT credentials')
@@ -261,6 +230,7 @@ export const mapCredentialToAccept = async (args: MapCredentialToAcceptArgs): Pr
261
230
  ? uniformVerifiableCredential.decodedPayload.iss
262
231
  : uniformVerifiableCredential.issuer.id
263
232
 
233
+ const credentialResponse = credentialToAccept.credentialResponse as CredentialResponseV1_0_15
264
234
  return {
265
235
  correlationId,
266
236
  credentialToAccept,
@@ -271,6 +241,27 @@ export const mapCredentialToAccept = async (args: MapCredentialToAcceptArgs): Pr
271
241
  }
272
242
  }
273
243
 
244
+ export const extractCredentialFromResponse = (credentialResponse: CredentialResponse): OriginalVerifiableCredential => {
245
+ let credential: OriginalVerifiableCredential | undefined
246
+
247
+ if ('credential' in credentialResponse) {
248
+ credential = credentialResponse.credential as OriginalVerifiableCredential
249
+ } else if (
250
+ 'credentials' in credentialResponse &&
251
+ credentialResponse.credentials &&
252
+ Array.isArray(credentialResponse.credentials) &&
253
+ credentialResponse.credentials.length > 0
254
+ ) {
255
+ credential = credentialResponse.credentials[0].credential as OriginalVerifiableCredential // FIXME SSISDK-13 (no multi-credential support yet)
256
+ }
257
+
258
+ if (!credential) {
259
+ throw new Error('No credential found in credential response')
260
+ }
261
+
262
+ return credential
263
+ }
264
+
274
265
  export const getIdentifierOpts = async (args: GetIdentifierArgs): Promise<ManagedIdentifierResult> => {
275
266
  const { issuanceOpt, context } = args
276
267
  const { identifier: identifierArg } = issuanceOpt
@@ -391,7 +382,7 @@ export const getCredentialConfigsSupportedBySingleTypeOrId = async (
391
382
  }
392
383
 
393
384
  if (configurationId) {
394
- const allSupported = client.getCredentialsSupported(false)
385
+ const allSupported = client.getCredentialsSupported(undefined, format)
395
386
  return Object.fromEntries(
396
387
  Object.entries(allSupported).filter(
397
388
  ([id, supported]) => id === configurationId || supported.id === configurationId || createIdFromTypes(supported) === configurationId,
@@ -399,29 +390,15 @@ export const getCredentialConfigsSupportedBySingleTypeOrId = async (
399
390
  )
400
391
  }
401
392
 
402
- if (!types && !client.credentialOffer) {
403
- return Promise.reject(Error('openID4VCIClient has no credentialOffer and no types where provided'))
404
- /*} else if (!format && !client.credentialOffer) {
405
- return Promise.reject(Error('openID4VCIClient has no credentialOffer and no formats where provided'))*/
393
+ if (!client.credentialOffer) {
394
+ return Promise.reject(Error('openID4VCIClient has no credentialOffer'))
406
395
  }
407
- // We should always have a credential offer at this point given the above
408
- if (!Array.isArray(format) && client.credentialOffer) {
409
- if (
410
- client.version() > OpenId4VCIVersion.VER_1_0_09 &&
411
- typeof client.credentialOffer.credential_offer === 'object' &&
412
- 'credentials' in client.credentialOffer.credential_offer
413
- ) {
414
- format = client.credentialOffer.credential_offer.credentials
415
- .filter((cred: CredentialOfferFormatV1_0_11 | string) => typeof cred !== 'string')
416
- .map((cred: CredentialOfferFormatV1_0_11 | string) => (cred as CredentialOfferFormatV1_0_11).format)
417
- if (format?.length === 0) {
418
- format = undefined // Otherwise we would match nothing
419
- }
420
- }
396
+ if (!types) {
397
+ return Promise.reject(Error('openID4VCIClient has no types'))
421
398
  }
422
399
 
423
400
  const offerSupported = getSupportedCredentials({
424
- types: types ? [types] : client.getCredentialOfferTypes(),
401
+ types: [types],
425
402
  format,
426
403
  version: client.version(),
427
404
  issuerMetadata: client.endpointMetadata.credentialIssuerMetadata,
@@ -601,7 +578,7 @@ export const getIssuanceCryptoSuite = async (opts: GetIssuanceCryptoSuiteArgs):
601
578
  case 'jwt':
602
579
  case 'jwt_vc_json':
603
580
  case 'jwt_vc':
604
- case 'vc+sd-jwt':
581
+ //case 'vc+sd-jwt': // TODO see SSISDK-52 concerning vc+sd-jwt
605
582
  case 'dc+sd-jwt':
606
583
  case 'mso_mdoc': {
607
584
  const supportedPreferences: Array<JoseSignatureAlgorithm | JoseSignatureAlgorithmString> = jwtCryptographicSuitePreferences.filter(