@sphereon/ssi-sdk.siopv2-oid4vp-op-auth 0.32.1-feature.VDX.341.57 → 0.32.1-feature.new.develop.274

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.
Files changed (38) hide show
  1. package/dist/agent/DidAuthSiopOpAuthenticator.d.ts +5 -5
  2. package/dist/agent/DidAuthSiopOpAuthenticator.d.ts.map +1 -1
  3. package/dist/agent/DidAuthSiopOpAuthenticator.js +85 -64
  4. package/dist/agent/DidAuthSiopOpAuthenticator.js.map +1 -1
  5. package/dist/services/Siopv2MachineService.d.ts +4 -3
  6. package/dist/services/Siopv2MachineService.d.ts.map +1 -1
  7. package/dist/services/Siopv2MachineService.js +24 -16
  8. package/dist/services/Siopv2MachineService.js.map +1 -1
  9. package/dist/session/OID4VP.d.ts +4 -4
  10. package/dist/session/OID4VP.d.ts.map +1 -1
  11. package/dist/session/OID4VP.js.map +1 -1
  12. package/dist/session/OpSession.d.ts.map +1 -1
  13. package/dist/session/OpSession.js +3 -3
  14. package/dist/session/OpSession.js.map +1 -1
  15. package/dist/types/IDidAuthSiopOpAuthenticator.d.ts +12 -8
  16. package/dist/types/IDidAuthSiopOpAuthenticator.d.ts.map +1 -1
  17. package/dist/types/IDidAuthSiopOpAuthenticator.js.map +1 -1
  18. package/dist/types/machine/index.d.ts +1 -0
  19. package/dist/types/machine/index.d.ts.map +1 -1
  20. package/dist/types/machine/index.js.map +1 -1
  21. package/dist/types/siop-service/index.d.ts +20 -5
  22. package/dist/types/siop-service/index.d.ts.map +1 -1
  23. package/dist/types/siop-service/index.js.map +1 -1
  24. package/dist/utils/CredentialUtils.d.ts.map +1 -1
  25. package/dist/utils/CredentialUtils.js.map +1 -1
  26. package/dist/utils/dcql.d.ts +2 -2
  27. package/dist/utils/dcql.d.ts.map +1 -1
  28. package/dist/utils/dcql.js.map +1 -1
  29. package/package.json +22 -22
  30. package/src/agent/DidAuthSiopOpAuthenticator.ts +108 -90
  31. package/src/services/Siopv2MachineService.ts +20 -11
  32. package/src/session/OID4VP.ts +6 -6
  33. package/src/session/OpSession.ts +8 -6
  34. package/src/types/IDidAuthSiopOpAuthenticator.ts +21 -9
  35. package/src/types/machine/index.ts +1 -0
  36. package/src/types/siop-service/index.ts +23 -5
  37. package/src/utils/CredentialUtils.ts +2 -2
  38. package/src/utils/dcql.ts +2 -2
@@ -10,13 +10,14 @@ import {
10
10
  NonPersistedIdentity,
11
11
  Party,
12
12
  } from '@sphereon/ssi-sdk.data-store'
13
- import { Hasher, Loggers } from '@sphereon/ssi-types'
13
+ import { HasherSync, Loggers, SdJwtDecodedVerifiableCredential } from '@sphereon/ssi-types'
14
14
  import { IAgentPlugin } from '@veramo/core'
15
15
  import { v4 as uuidv4 } from 'uuid'
16
16
  import {
17
17
  DidAuthSiopOpAuthenticatorOptions,
18
18
  GetSelectableCredentialsArgs,
19
19
  IOpSessionArgs,
20
+ Json,
20
21
  LOGGER_NAMESPACE,
21
22
  RequiredContext,
22
23
  schema,
@@ -27,6 +28,10 @@ import {
27
28
  import { Siopv2Machine } from '../machine/Siopv2Machine'
28
29
  import { getSelectableCredentials, siopSendAuthorizationResponse, translateCorrelationIdToName } from '../services/Siopv2MachineService'
29
30
  import { OpSession } from '../session'
31
+ import { PEX, Status } from '@sphereon/pex'
32
+ import { computeEntryHash } from '@veramo/utils'
33
+ import { UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'
34
+ import { EventEmitter } from 'events'
30
35
  import {
31
36
  IDidAuthSiopOpAuthenticator,
32
37
  IGetSiopSessionArgs,
@@ -34,8 +39,7 @@ import {
34
39
  IRemoveCustomApprovalForSiopArgs,
35
40
  IRemoveSiopSessionArgs,
36
41
  IRequiredContext,
37
- } from '../types/IDidAuthSiopOpAuthenticator'
38
- import { Siopv2Machine as Siopv2MachineId, Siopv2MachineInstanceOpts } from '../types/machine'
42
+ } from '../types'
39
43
 
40
44
  import {
41
45
  AddIdentityArgs,
@@ -48,12 +52,10 @@ import {
48
52
  SendResponseArgs,
49
53
  Siopv2AuthorizationRequestData,
50
54
  Siopv2HolderEvent,
51
- } from '../types/siop-service'
52
- import { PEX, Status } from '@sphereon/pex'
53
- import { computeEntryHash } from '@veramo/utils'
54
- import { UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'
55
- import { EventEmitter } from 'events'
56
- import { DcqlCredential, DcqlPresentation, DcqlQuery } from 'dcql'
55
+ Siopv2Machine as Siopv2MachineId,
56
+ Siopv2MachineInstanceOpts,
57
+ } from '../types'
58
+ import { DcqlCredential, DcqlPresentation, DcqlQuery, DcqlSdJwtVcCredential } from 'dcql'
57
59
 
58
60
  const logger = Loggers.DEFAULT.options(LOGGER_NAMESPACE, {}).get(LOGGER_NAMESPACE)
59
61
 
@@ -92,26 +94,20 @@ export class DidAuthSiopOpAuthenticator implements IAgentPlugin {
92
94
  private readonly sessions: Map<string, OpSession>
93
95
  private readonly customApprovals: Record<string, (verifiedAuthorizationRequest: VerifiedAuthorizationRequest, sessionId: string) => Promise<void>>
94
96
  private readonly presentationSignCallback?: PresentationSignCallback
95
-
96
97
  private readonly onContactIdentityCreated?: (args: OnContactIdentityCreatedArgs) => Promise<void>
97
98
  private readonly onIdentifierCreated?: (args: OnIdentifierCreatedArgs) => Promise<void>
98
99
  private readonly eventEmitter?: EventEmitter
99
- private readonly hasher: Hasher | undefined
100
-
101
- constructor(
102
- presentationSignCallback?: PresentationSignCallback,
103
- customApprovals?: Record<string, (verifiedAuthorizationRequest: VerifiedAuthorizationRequest, sessionId: string) => Promise<void>>,
104
- options?: DidAuthSiopOpAuthenticatorOptions,
105
- hasher?: Hasher, // FIXME BEFORE PR move into DidAuthSiopOpAuthenticatorOptions (move everything into options like we do with the rest of the agent plugins)
106
- ) {
107
- const { onContactIdentityCreated, onIdentifierCreated } = options ?? {}
100
+ private readonly hasher?: HasherSync
101
+
102
+ constructor(options?: DidAuthSiopOpAuthenticatorOptions) {
103
+ const { onContactIdentityCreated, onIdentifierCreated, hasher, customApprovals = {}, presentationSignCallback } = { ...options }
104
+
105
+ this.hasher = hasher
108
106
  this.onContactIdentityCreated = onContactIdentityCreated
109
107
  this.onIdentifierCreated = onIdentifierCreated
110
-
111
- this.sessions = new Map<string, OpSession>()
112
- this.customApprovals = customApprovals || {}
113
108
  this.presentationSignCallback = presentationSignCallback
114
- this.hasher = hasher
109
+ this.sessions = new Map<string, OpSession>()
110
+ this.customApprovals = customApprovals
115
111
  }
116
112
 
117
113
  public async onEvent(event: any, context: RequiredContext): Promise<void> {
@@ -191,8 +187,8 @@ export class DidAuthSiopOpAuthenticator implements IAgentPlugin {
191
187
  return Siopv2Machine.newInstance(siopv2MachineOpts)
192
188
  }
193
189
 
194
- private async siopCreateConfig(args: CreateConfigArgs): Promise<CreateConfigResult> {
195
- const { url } = args
190
+ private async siopCreateConfig<TContext extends CreateConfigArgs>(context: TContext): Promise<CreateConfigResult> {
191
+ const { url } = context
196
192
 
197
193
  if (!url) {
198
194
  return Promise.reject(Error('Missing request uri in context'))
@@ -219,9 +215,14 @@ export class DidAuthSiopOpAuthenticator implements IAgentPlugin {
219
215
  }
220
216
  const { sessionId, redirectUrl } = didAuthConfig
221
217
 
222
- const session: OpSession = await agent
223
- .siopGetOPSession({ sessionId })
224
- .catch(async () => await agent.siopRegisterOPSession({ requestJwtOrUri: redirectUrl, sessionId, op: { eventEmitter: this.eventEmitter } }))
218
+ const session: OpSession = await agent.siopGetOPSession({ sessionId }).catch(
219
+ async () =>
220
+ await agent.siopRegisterOPSession({
221
+ requestJwtOrUri: redirectUrl,
222
+ sessionId,
223
+ op: { eventEmitter: this.eventEmitter, hasher: this.hasher },
224
+ }),
225
+ )
225
226
 
226
227
  logger.debug(`session: ${JSON.stringify(session.id, null, 2)}`)
227
228
  const verifiedAuthorizationRequest = await session.getAuthorizationRequest()
@@ -339,7 +340,7 @@ export class DidAuthSiopOpAuthenticator implements IAgentPlugin {
339
340
  }
340
341
 
341
342
  private async siopSendResponse(args: SendResponseArgs, context: RequiredContext): Promise<Siopv2AuthorizationResponseData> {
342
- const { didAuthConfig, authorizationRequestData, selectedCredentials } = args
343
+ const { didAuthConfig, authorizationRequestData, selectedCredentials, isFirstParty } = args
343
344
 
344
345
  if (didAuthConfig === undefined) {
345
346
  return Promise.reject(Error('Missing config in context'))
@@ -349,65 +350,74 @@ export class DidAuthSiopOpAuthenticator implements IAgentPlugin {
349
350
  return Promise.reject(Error('Missing authorization request data in context'))
350
351
  }
351
352
 
352
- const pex = new PEX()
353
+ const pex = new PEX({ hasher: this.hasher })
353
354
  const verifiableCredentialsWithDefinition: Array<VerifiableCredentialsWithDefinition> = []
354
355
  const dcqlCredentialsWithCredentials: Map<DcqlCredential, UniqueDigitalCredential> = new Map()
355
356
 
356
- if (authorizationRequestData.presentationDefinitions !== undefined && authorizationRequestData.presentationDefinitions !== null) {
357
- authorizationRequestData.presentationDefinitions?.forEach((presentationDefinition) => {
358
- const { areRequiredCredentialsPresent, verifiableCredential: verifiableCredentials } = pex.selectFrom(
359
- presentationDefinition.definition,
360
- selectedCredentials.map((udc) => udc.originalVerifiableCredential!),
361
- )
362
-
363
- if (areRequiredCredentialsPresent !== Status.ERROR && verifiableCredentials) {
364
- const uniqueDigitalCredentials: UniqueDigitalCredential[] = verifiableCredentials.map((vc) => {
365
- // @ts-ignore FIXME Funke
366
- const hash = computeEntryHash(vc)
367
- const udc = selectedCredentials.find((udc) => udc.hash == hash)
368
-
369
- if (!udc) {
370
- throw Error('UniqueDigitalCredential could not be found')
371
- }
372
- return udc
373
- })
374
- verifiableCredentialsWithDefinition.push({
375
- definition: presentationDefinition,
376
- credentials: uniqueDigitalCredentials,
377
- })
378
- }
379
- })
357
+ if (Array.isArray(authorizationRequestData.presentationDefinitions) && authorizationRequestData?.presentationDefinitions.length > 0) {
358
+ try {
359
+ authorizationRequestData.presentationDefinitions?.forEach((presentationDefinition) => {
360
+ const { areRequiredCredentialsPresent, verifiableCredential: verifiableCredentials } = pex.selectFrom(
361
+ presentationDefinition.definition,
362
+ selectedCredentials.map((udc) => udc.originalVerifiableCredential!),
363
+ )
364
+
365
+ if (areRequiredCredentialsPresent !== Status.ERROR && verifiableCredentials) {
366
+ let uniqueDigitalCredentials: UniqueDigitalCredential[] = []
367
+ uniqueDigitalCredentials = verifiableCredentials.map((vc) => {
368
+ // @ts-ignore FIXME Funke
369
+ const hash = typeof vc === 'string' ? computeEntryHash(vc.split('~'[0])) : computeEntryHash(vc)
370
+ const udc = selectedCredentials.find((udc) => udc.hash == hash || udc.originalVerifiableCredential == vc)
371
+
372
+ if (!udc) {
373
+ throw Error(
374
+ `UniqueDigitalCredential could not be found in store. Either the credential is not present in the store or the hash is not correct.`,
375
+ )
376
+ }
377
+ return udc
378
+ })
379
+ verifiableCredentialsWithDefinition.push({
380
+ definition: presentationDefinition,
381
+ credentials: uniqueDigitalCredentials,
382
+ })
383
+ }
384
+ })
385
+ } catch (e) {
386
+ return Promise.reject(e)
387
+ }
380
388
 
381
389
  if (verifiableCredentialsWithDefinition.length === 0) {
382
390
  return Promise.reject(Error('None of the selected credentials match any of the presentation definitions.'))
383
391
  }
384
- } else if (authorizationRequestData.dcqlQuery !== undefined && authorizationRequestData.dcqlQuery !== null) {
392
+ } else if (authorizationRequestData.dcqlQuery) {
385
393
  //TODO Only SD-JWT and MSO MDOC are supported at the moment
386
394
  if (this.hasMDocCredentials(selectedCredentials) || this.hasSdJwtCredentials(selectedCredentials)) {
387
- selectedCredentials.forEach((vc: any) => {
388
- const payload =
389
- vc['decodedPayload'] !== undefined && vc['decodedPayload'] !== null
390
- ? vc.decodedPayload
391
- : vc['decoded'] !== undefined && vc['decoded'] !== null
392
- ? vc.decoded
393
- : undefined
394
- const vct = payload?.vct
395
- const docType = payload?.docType
396
- const namespaces = payload?.namespaces
397
- const result: DcqlCredential = {
398
- claims: payload,
399
- vct,
400
- docType,
401
- namespaces,
402
- }
403
- dcqlCredentialsWithCredentials.set(result, vc)
404
- })
395
+ try {
396
+ selectedCredentials.forEach((vc) => {
397
+ if (this.isSdJwtCredential(vc)) {
398
+ const payload = (vc.originalVerifiableCredential as SdJwtDecodedVerifiableCredential).decodedPayload
399
+ const result: DcqlSdJwtVcCredential = {
400
+ claims: payload as { [x: string]: Json },
401
+ vct: payload.vct,
402
+ credential_format: 'vc+sd-jwt',
403
+ }
404
+ dcqlCredentialsWithCredentials.set(result, vc)
405
+ //FIXME MDoc namespaces are incompatible: array of strings vs complex object - https://sphereon.atlassian.net/browse/SPRIND-143
406
+ } else {
407
+ throw Error(`Invalid credential format: ${vc.digitalCredential.documentFormat}`)
408
+ }
409
+ })
410
+ } catch (e) {
411
+ return Promise.reject(e)
412
+ }
405
413
 
406
- const dcqlPresentationRecord: DcqlPresentation = {}
414
+ const dcqlPresentationRecord: DcqlPresentation.Output = {}
407
415
  const queryResult = DcqlQuery.query(authorizationRequestData.dcqlQuery, Array.from(dcqlCredentialsWithCredentials.keys()))
408
416
  for (const [key, value] of Object.entries(queryResult.credential_matches)) {
409
417
  if (value.success) {
410
- dcqlPresentationRecord[key] = this.retrieveEncodedCredential(dcqlCredentialsWithCredentials.get(value.output)!)
418
+ dcqlPresentationRecord[key] = this.retrieveEncodedCredential(dcqlCredentialsWithCredentials.get(value.output)!) as
419
+ | string
420
+ | { [x: string]: Json }
411
421
  }
412
422
  }
413
423
  }
@@ -419,15 +429,16 @@ export class DidAuthSiopOpAuthenticator implements IAgentPlugin {
419
429
  sessionId: didAuthConfig.sessionId,
420
430
  ...(args.idOpts && { idOpts: args.idOpts }),
421
431
  ...(authorizationRequestData.presentationDefinitions !== undefined && { verifiableCredentialsWithDefinition }),
432
+ isFirstParty,
422
433
  hasher: this.hasher,
423
434
  },
424
435
  context,
425
436
  )
426
437
 
427
- const contentType = response?.headers.get('content-type') || ''
438
+ const contentType = response.headers.get('content-type') || ''
428
439
  let responseBody: any = null
429
440
 
430
- const text = await response?.text()
441
+ const text = await response.text()
431
442
  if (text) {
432
443
  responseBody = contentType.includes('application/json') || text.startsWith('{') ? JSON.parse(text) : text
433
444
  }
@@ -435,31 +446,38 @@ export class DidAuthSiopOpAuthenticator implements IAgentPlugin {
435
446
  return {
436
447
  body: responseBody,
437
448
  url: response?.url,
438
- queryParams: response && decodeUriAsJson(response?.url),
449
+ queryParams: decodeUriAsJson(response?.url),
439
450
  }
440
451
  }
441
452
 
442
453
  private hasMDocCredentials = (credentials: UniqueDigitalCredential[]): boolean => {
443
- return credentials.some(
444
- (credential) =>
445
- credential.digitalCredential.documentFormat === CredentialDocumentFormat.MSO_MDOC &&
446
- credential.digitalCredential.documentType === DocumentType.VC,
454
+ return credentials.some(this.isMDocCredential)
455
+ }
456
+
457
+ private isMDocCredential = (credential: UniqueDigitalCredential) => {
458
+ return (
459
+ credential.digitalCredential.documentFormat === CredentialDocumentFormat.MSO_MDOC &&
460
+ credential.digitalCredential.documentType === DocumentType.VC
447
461
  )
448
462
  }
449
463
 
450
464
  private hasSdJwtCredentials = (credentials: UniqueDigitalCredential[]): boolean => {
451
- return credentials.some(
452
- (credential) =>
453
- credential.digitalCredential.documentFormat === CredentialDocumentFormat.SD_JWT &&
454
- credential.digitalCredential.documentType === DocumentType.VC,
465
+ return credentials.some(this.isSdJwtCredential)
466
+ }
467
+
468
+ private isSdJwtCredential = (credential: UniqueDigitalCredential) => {
469
+ return (
470
+ credential.digitalCredential.documentFormat === CredentialDocumentFormat.SD_JWT && credential.digitalCredential.documentType === DocumentType.VC
455
471
  )
456
472
  }
457
473
 
458
474
  private retrieveEncodedCredential = (credential: UniqueDigitalCredential) => {
459
- // FIXME Remove any
460
- return (credential as any).original !== undefined && (credential as any).original !== null
461
- ? (credential as any).original
462
- : (credential as any).compactSdJwtVc
475
+ return credential.originalVerifiableCredential !== undefined &&
476
+ credential.originalVerifiableCredential !== null &&
477
+ (credential?.originalVerifiableCredential as SdJwtDecodedVerifiableCredential)?.compactSdJwtVc !== undefined &&
478
+ (credential?.originalVerifiableCredential as SdJwtDecodedVerifiableCredential)?.compactSdJwtVc !== null
479
+ ? (credential.originalVerifiableCredential as SdJwtDecodedVerifiableCredential).compactSdJwtVc
480
+ : credential.originalVerifiableCredential
463
481
  }
464
482
 
465
483
  private async siopGetSelectableCredentials(args: GetSelectableCredentialsArgs, context: RequiredContext): Promise<SelectableCredentialsMap> {
@@ -4,7 +4,7 @@ import { InputDescriptorV1, InputDescriptorV2, PresentationDefinitionV1, Present
4
4
  import { isOID4VCIssuerIdentifier, ManagedIdentifierOptsOrResult } from '@sphereon/ssi-sdk-ext.identifier-resolution'
5
5
  import { UniqueDigitalCredential, verifiableCredentialForRoleFilter } from '@sphereon/ssi-sdk.credential-store'
6
6
  import { ConnectionType, CredentialRole } from '@sphereon/ssi-sdk.data-store'
7
- import { CredentialMapper, Hasher, Loggers, OriginalVerifiableCredential, PresentationSubmission } from '@sphereon/ssi-types'
7
+ import { CredentialMapper, HasherSync, Loggers, OriginalVerifiableCredential, PresentationSubmission } from '@sphereon/ssi-types'
8
8
  import { OID4VP, OpSession } from '../session'
9
9
  import {
10
10
  DidAgents,
@@ -20,7 +20,7 @@ import {
20
20
  import { IAgentContext, IDIDManager } from '@veramo/core'
21
21
  import { getOrCreatePrimaryIdentifier, SupportedDidMethodEnum } from '@sphereon/ssi-sdk-ext.did-utils'
22
22
  import { encodeJoseBlob } from '@sphereon/ssi-sdk.core'
23
- import { DcqlCredential, DcqlQuery, DcqlCredentialPresentation, DcqlPresentation } from 'dcql'
23
+ import { DcqlCredential, DcqlCredentialPresentation, DcqlPresentation, DcqlQuery } from 'dcql'
24
24
  import { convertToDcqlCredentials } from '../utils/dcql'
25
25
  import { getOriginalVerifiableCredential } from '../utils/CredentialUtils'
26
26
 
@@ -51,14 +51,15 @@ export const siopSendAuthorizationResponse = async (
51
51
  sessionId: string
52
52
  verifiableCredentialsWithDefinition?: VerifiableCredentialsWithDefinition[]
53
53
  idOpts?: ManagedIdentifierOptsOrResult
54
+ isFirstParty?: boolean
55
+ hasher?: HasherSync
54
56
  dcqlQuery?: DcqlQuery
55
- hasher?: Hasher
56
57
  },
57
58
  context: RequiredContext,
58
59
  ) => {
59
60
  const { agent } = context
60
61
  const agentContext = { ...context, agent: context.agent as DidAgents }
61
- let { idOpts } = args
62
+ let { idOpts, isFirstParty, hasher } = args
62
63
 
63
64
  if (connectionType !== ConnectionType.SIOPv2_OpenID4VP) {
64
65
  return Promise.reject(Error(`No supported authentication provider for type: ${connectionType}`))
@@ -72,7 +73,7 @@ export const siopSendAuthorizationResponse = async (
72
73
  let presentationsAndDefs: VerifiablePresentationWithDefinition[] | undefined
73
74
  let presentationSubmission: PresentationSubmission | undefined
74
75
  if (await session.hasPresentationDefinitions()) {
75
- const oid4vp: OID4VP = await session.getOID4VP({})
76
+ const oid4vp: OID4VP = await session.getOID4VP({ hasher })
76
77
 
77
78
  const credentialsAndDefinitions = args.verifiableCredentialsWithDefinition
78
79
  ? args.verifiableCredentialsWithDefinition
@@ -128,11 +129,18 @@ export const siopSendAuthorizationResponse = async (
128
129
  break
129
130
  // TODO other implementations?
130
131
  default:
131
- // Since we are using the kmsKeyRef we will find the KID regardless of the identifier. We set it for later access though
132
- identifier = await session.context.agent.identifierManagedGetByKid({
133
- identifier: digitalCredential.subjectCorrelationId ?? holder ?? digitalCredential.kmsKeyRef,
134
- kmsKeyRef: digitalCredential.kmsKeyRef,
135
- })
132
+ if (digitalCredential.subjectCorrelationId?.startsWith('did:') || holder?.startsWith('did:')) {
133
+ identifier = await session.context.agent.identifierManagedGetByDid({
134
+ identifier: digitalCredential.subjectCorrelationId ?? holder,
135
+ kmsKeyRef: digitalCredential.kmsKeyRef,
136
+ })
137
+ } else {
138
+ // Since we are using the kmsKeyRef we will find the KID regardless of the identifier. We set it for later access though
139
+ identifier = await session.context.agent.identifierManagedGetByKid({
140
+ identifier: digitalCredential.subjectCorrelationId ?? holder ?? digitalCredential.kmsKeyRef,
141
+ kmsKeyRef: digitalCredential.kmsKeyRef,
142
+ })
143
+ }
136
144
  }
137
145
  }
138
146
 
@@ -167,6 +175,7 @@ export const siopSendAuthorizationResponse = async (
167
175
  ...(presentationSubmission && { presentationSubmission }),
168
176
  // todo: Change issuer value in case we do not use identifier. Use key.meta.jwkThumbprint then
169
177
  responseSignerOpts: idOpts!,
178
+ isFirstParty,
170
179
  })
171
180
  } else if (request.dcqlQuery) {
172
181
  if (args.verifiableCredentialsWithDefinition !== undefined && args.verifiableCredentialsWithDefinition !== null) {
@@ -266,7 +275,7 @@ export const siopSendAuthorizationResponse = async (
266
275
  return response
267
276
  }
268
277
  }
269
- return undefined
278
+ throw Error('Presentation Definition or DCQL is required')
270
279
  }
271
280
 
272
281
  function buildPartialPD(
@@ -2,15 +2,15 @@ import { PresentationDefinitionWithLocation, PresentationExchange } from '@spher
2
2
  import { SelectResults, Status, SubmissionRequirementMatch } from '@sphereon/pex'
3
3
  import { Format } from '@sphereon/pex-models'
4
4
  import {
5
- isOID4VCIssuerIdentifier,
6
5
  isManagedIdentifierDidResult,
6
+ isOID4VCIssuerIdentifier,
7
7
  ManagedIdentifierOptsOrResult,
8
8
  ManagedIdentifierResult,
9
9
  } from '@sphereon/ssi-sdk-ext.identifier-resolution'
10
10
  import { ProofOptions } from '@sphereon/ssi-sdk.core'
11
11
  import { UniqueDigitalCredential, verifiableCredentialForRoleFilter } from '@sphereon/ssi-sdk.credential-store'
12
12
  import { CredentialRole, FindDigitalCredentialArgs } from '@sphereon/ssi-sdk.data-store'
13
- import { CompactJWT, Hasher, IProof, OriginalVerifiableCredential } from '@sphereon/ssi-types'
13
+ import { CompactJWT, HasherSync, IProof, OriginalVerifiableCredential } from '@sphereon/ssi-types'
14
14
  import {
15
15
  DEFAULT_JWT_PROOF_TYPE,
16
16
  IGetPresentationExchangeArgs,
@@ -24,7 +24,7 @@ import { OpSession } from './OpSession'
24
24
  export class OID4VP {
25
25
  private readonly session: OpSession
26
26
  private readonly allIdentifiers: string[]
27
- private readonly hasher?: Hasher
27
+ private readonly hasher?: HasherSync
28
28
 
29
29
  private constructor(args: IOID4VPArgs) {
30
30
  const { session, allIdentifiers, hasher } = args
@@ -34,7 +34,7 @@ export class OID4VP {
34
34
  this.hasher = hasher
35
35
  }
36
36
 
37
- public static async init(session: OpSession, allIdentifiers: string[], hasher?: Hasher): Promise<OID4VP> {
37
+ public static async init(session: OpSession, allIdentifiers: string[], hasher?: HasherSync): Promise<OID4VP> {
38
38
  return new OID4VP({ session, allIdentifiers: allIdentifiers ?? (await session.getSupportedDIDs()), hasher })
39
39
  }
40
40
 
@@ -68,7 +68,7 @@ export class OID4VP {
68
68
  skipDidResolution?: boolean
69
69
  holderDID?: string
70
70
  subjectIsHolder?: boolean
71
- hasher?: Hasher
71
+ hasher?: HasherSync
72
72
  applyFilter?: boolean
73
73
  },
74
74
  ): Promise<VerifiablePresentationWithDefinition[]> {
@@ -88,7 +88,7 @@ export class OID4VP {
88
88
  holder?: string
89
89
  subjectIsHolder?: boolean
90
90
  applyFilter?: boolean
91
- hasher?: Hasher
91
+ hasher?: HasherSync
92
92
  },
93
93
  ): Promise<VerifiablePresentationWithDefinition> {
94
94
  const { subjectIsHolder, holder, forceNoCredentialsInVP = false } = { ...opts }
@@ -20,10 +20,11 @@ import { encodeBase64url } from '@sphereon/ssi-sdk.core'
20
20
  import {
21
21
  CompactSdJwtVc,
22
22
  CredentialMapper,
23
- Hasher, OriginalVerifiableCredential,
23
+ HasherSync,
24
+ OriginalVerifiableCredential,
24
25
  parseDid,
25
26
  PresentationSubmission,
26
- W3CVerifiablePresentation
27
+ W3CVerifiablePresentation,
27
28
  } from '@sphereon/ssi-types'
28
29
  import { IIdentifier, IVerifyResult, TKeyType } from '@veramo/core'
29
30
  import Debug from 'debug'
@@ -292,8 +293,8 @@ export class OpSession {
292
293
  .jwtEncryptJweCompactJwt({
293
294
  recipientKey,
294
295
  protectedHeader: {},
295
- alg: requestObjectPayload.client_metadata.authorization_encrypted_response_alg as JweAlg | undefined ?? 'ECDH-ES',
296
- enc: requestObjectPayload.client_metadata.authorization_encrypted_response_enc as JweEnc | undefined ?? 'A256GCM',
296
+ alg: (requestObjectPayload.client_metadata.authorization_encrypted_response_alg as JweAlg | undefined) ?? 'ECDH-ES',
297
+ enc: (requestObjectPayload.client_metadata.authorization_encrypted_response_enc as JweEnc | undefined) ?? 'A256GCM',
297
298
  apv: encodeBase64url(opts.requestObjectPayload.nonce),
298
299
  apu: encodeBase64url(v4()),
299
300
  payload: authResponse,
@@ -359,13 +360,14 @@ export class OpSession {
359
360
  const responseOpts = {
360
361
  verification,
361
362
  issuer,
363
+ ...(args.isFirstParty && { isFirstParty: args.isFirstParty }),
362
364
  ...(args.verifiablePresentations && {
363
365
  presentationExchange: {
364
366
  verifiablePresentations,
365
367
  presentationSubmission: args.presentationSubmission,
366
368
  } as PresentationExchangeResponseOpts,
367
369
  }),
368
- dcqlQuery: args.dcqlQuery
370
+ dcqlQuery: args.dcqlResponse,
369
371
  }
370
372
 
371
373
  const authResponse = await op.createAuthorizationResponse(request, responseOpts)
@@ -378,7 +380,7 @@ export class OpSession {
378
380
  }
379
381
  }
380
382
 
381
- private countVCsInAllVPs(verifiablePresentations: W3CVerifiablePresentation[], hasher?: Hasher) {
383
+ private countVCsInAllVPs(verifiablePresentations: W3CVerifiablePresentation[], hasher?: HasherSync) {
382
384
  return verifiablePresentations.reduce((sum, vp) => {
383
385
  if (CredentialMapper.isMsoMdocDecodedPresentation(vp) || CredentialMapper.isMsoMdocOid4VPEncoded(vp)) {
384
386
  return sum + 1
@@ -1,5 +1,5 @@
1
1
  import {
2
- DcqlQueryResponseOpts,
2
+ DcqlResponseOpts,
3
3
  PresentationDefinitionWithLocation,
4
4
  PresentationSignCallback,
5
5
  ResponseMode,
@@ -19,7 +19,7 @@ import { ICredentialStore, UniqueDigitalCredential } from '@sphereon/ssi-sdk.cre
19
19
  import { Party } from '@sphereon/ssi-sdk.data-store'
20
20
  import { IPDManager } from '@sphereon/ssi-sdk.pd-manager'
21
21
  import { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt'
22
- import { Hasher, OriginalVerifiableCredential, PresentationSubmission, W3CVerifiablePresentation } from '@sphereon/ssi-types'
22
+ import { HasherSync, OriginalVerifiableCredential, PresentationSubmission, W3CVerifiablePresentation } from '@sphereon/ssi-types'
23
23
  import { VerifyCallback } from '@sphereon/wellknown-dids-client'
24
24
  import {
25
25
  IAgentContext,
@@ -123,8 +123,9 @@ export interface IOpsSendSiopAuthorizationResponseArgs {
123
123
  // verifiedAuthorizationRequest: VerifiedAuthorizationRequest
124
124
  presentationSubmission?: PresentationSubmission
125
125
  verifiablePresentations?: W3CVerifiablePresentation[]
126
- dcqlQuery?: DcqlQueryResponseOpts
127
- hasher?: Hasher
126
+ dcqlResponse?: DcqlResponseOpts
127
+ hasher?: HasherSync
128
+ isFirstParty?: boolean
128
129
  }
129
130
 
130
131
  export enum events {
@@ -161,7 +162,7 @@ export interface IOPOptions {
161
162
  presentationSignCallback?: PresentationSignCallback
162
163
 
163
164
  resolveOpts?: ResolveOpts
164
- hasher?: Hasher
165
+ hasher?: HasherSync
165
166
  }
166
167
 
167
168
  /*
@@ -184,19 +185,30 @@ export interface VerifiablePresentationWithDefinition extends VerifiablePresenta
184
185
 
185
186
  export interface IOpSessionGetOID4VPArgs {
186
187
  allIdentifiers?: string[]
187
- hasher?: Hasher
188
+ hasher?: HasherSync
188
189
  }
189
190
 
190
191
  export interface IOID4VPArgs {
191
192
  session: OpSession
192
193
  allIdentifiers?: string[]
193
- hasher?: Hasher
194
+ hasher?: HasherSync
194
195
  }
195
196
 
196
197
  export interface IGetPresentationExchangeArgs {
197
198
  verifiableCredentials: OriginalVerifiableCredential[]
198
199
  allIdentifiers?: string[]
199
- hasher?: Hasher
200
- }
200
+ hasher?: HasherSync
201
+ }
202
+
203
+ // It was added here because it's not exported from DCQL anymore
204
+ export type Json =
205
+ | string
206
+ | number
207
+ | boolean
208
+ | null
209
+ | {
210
+ [key: string]: Json
211
+ }
212
+ | Json[]
201
213
 
202
214
  export const DEFAULT_JWT_PROOF_TYPE = 'JwtProof2020'
@@ -18,6 +18,7 @@ export type Siopv2MachineContext = {
18
18
  contactAlias: string
19
19
  selectableCredentialsMap?: SelectableCredentialsMap
20
20
  selectedCredentials: Array<UniqueDigitalCredential>
21
+ isFirstParty?: boolean
21
22
  error?: ErrorDetails
22
23
  }
23
24
 
@@ -1,4 +1,9 @@
1
- import { PresentationDefinitionWithLocation, RPRegistrationMetadataPayload } from '@sphereon/did-auth-siop'
1
+ import {
2
+ PresentationDefinitionWithLocation,
3
+ PresentationSignCallback,
4
+ RPRegistrationMetadataPayload,
5
+ VerifiedAuthorizationRequest,
6
+ } from '@sphereon/did-auth-siop'
2
7
  import { IIdentifierResolution, ManagedIdentifierOptsOrResult } from '@sphereon/ssi-sdk-ext.identifier-resolution'
3
8
  import { IContactManager } from '@sphereon/ssi-sdk.contact-manager'
4
9
  import { ICredentialStore, UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'
@@ -8,10 +13,14 @@ import { IAgentContext, IDIDManager, IIdentifier, IResolver } from '@veramo/core
8
13
  import { IDidAuthSiopOpAuthenticator } from '../IDidAuthSiopOpAuthenticator'
9
14
  import { Siopv2MachineContext, Siopv2MachineInterpreter, Siopv2MachineState } from '../machine'
10
15
  import { DcqlQuery } from 'dcql'
16
+ import { HasherSync } from '@sphereon/ssi-types'
11
17
 
12
18
  export type DidAuthSiopOpAuthenticatorOptions = {
19
+ presentationSignCallback?: PresentationSignCallback
20
+ customApprovals?: Record<string, (verifiedAuthorizationRequest: VerifiedAuthorizationRequest, sessionId: string) => Promise<void>>
13
21
  onContactIdentityCreated?: (args: OnContactIdentityCreatedArgs) => Promise<void>
14
22
  onIdentifierCreated?: (args: OnIdentifierCreatedArgs) => Promise<void>
23
+ hasher?: HasherSync
15
24
  }
16
25
 
17
26
  export type GetMachineArgs = {
@@ -20,12 +29,21 @@ export type GetMachineArgs = {
20
29
  stateNavigationListener?: (siopv2Machine: Siopv2MachineInterpreter, state: Siopv2MachineState, navigation?: any) => Promise<void>
21
30
  }
22
31
 
23
- export type CreateConfigArgs = Pick<Siopv2MachineContext, 'url'>
32
+ export type CreateConfigArgs = { url: string }
24
33
  export type CreateConfigResult = Omit<DidAuthConfig, 'stateId' | 'idOpts'>
25
- export type GetSiopRequestArgs = Pick<Siopv2MachineContext, 'didAuthConfig' | 'url'>
34
+ export type GetSiopRequestArgs = { didAuthConfig?: Omit<DidAuthConfig, 'identifier'>; url: string }
35
+ // FIXME it would be nicer if these function are not tied to a certain machine so that we can start calling them for anywhere
26
36
  export type RetrieveContactArgs = Pick<Siopv2MachineContext, 'url' | 'authorizationRequestData'>
37
+ // FIXME it would be nicer if these function are not tied to a certain machine so that we can start calling them for anywhere
27
38
  export type AddIdentityArgs = Pick<Siopv2MachineContext, 'contact' | 'authorizationRequestData'>
28
- export type SendResponseArgs = Pick<Siopv2MachineContext, 'didAuthConfig' | 'authorizationRequestData' | 'selectedCredentials' | 'idOpts'>
39
+ export type SendResponseArgs = {
40
+ didAuthConfig?: Omit<DidAuthConfig, 'identifier'>
41
+ authorizationRequestData?: Siopv2AuthorizationRequestData
42
+ selectedCredentials: Array<UniqueDigitalCredential>
43
+ idOpts?: ManagedIdentifierOptsOrResult
44
+ isFirstParty?: boolean
45
+ }
46
+ // FIXME it would be nicer if these function are not tied to a certain machine so that we can start calling them for anywhere
29
47
  export type GetSelectableCredentialsArgs = Pick<Siopv2MachineContext, 'authorizationRequestData'>
30
48
 
31
49
  export enum Siopv2HolderEvent {
@@ -39,7 +57,7 @@ export enum SupportedLanguage {
39
57
  }
40
58
 
41
59
  export type Siopv2AuthorizationResponseData = {
42
- body?: string
60
+ body?: string | Record<string, any>
43
61
  url?: string
44
62
  queryParams?: Record<string, any>
45
63
  }