@sphereon/ssi-sdk.oid4vci-holder 0.32.1-feature.VDX.341.56 → 0.32.1-feature.new.develop.273

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 (67) hide show
  1. package/dist/agent/OID4VCIHolder.d.ts.map +1 -1
  2. package/dist/agent/OID4VCIHolder.js +20 -14
  3. package/dist/agent/OID4VCIHolder.js.map +1 -1
  4. package/dist/index.d.ts +5 -2
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +5 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/link-handler/index.d.ts +3 -2
  9. package/dist/link-handler/index.d.ts.map +1 -1
  10. package/dist/link-handler/index.js +2 -1
  11. package/dist/link-handler/index.js.map +1 -1
  12. package/dist/listeners/headlessStateNavListener.d.ts.map +1 -0
  13. package/dist/listeners/headlessStateNavListener.js.map +1 -0
  14. package/dist/localization/translations/en.json +5 -1
  15. package/dist/localization/translations/nl.json +5 -1
  16. package/dist/machines/firstPartyMachine.d.ts +15 -0
  17. package/dist/machines/firstPartyMachine.d.ts.map +1 -0
  18. package/dist/machines/firstPartyMachine.js +222 -0
  19. package/dist/machines/firstPartyMachine.js.map +1 -0
  20. package/dist/machines/oid4vciMachine.d.ts.map +1 -0
  21. package/dist/{machine → machines}/oid4vciMachine.js +58 -2
  22. package/dist/machines/oid4vciMachine.js.map +1 -0
  23. package/dist/mappers/OIDC4VCIBrandingMapper.d.ts.map +1 -0
  24. package/dist/{agent → mappers}/OIDC4VCIBrandingMapper.js +1 -1
  25. package/dist/mappers/OIDC4VCIBrandingMapper.js.map +1 -0
  26. package/dist/services/FirstPartyMachineServices.d.ts +9 -0
  27. package/dist/services/FirstPartyMachineServices.d.ts.map +1 -0
  28. package/dist/services/FirstPartyMachineServices.js +53 -0
  29. package/dist/services/FirstPartyMachineServices.js.map +1 -0
  30. package/dist/{agent → services}/OID4VCIHolderService.d.ts +3 -2
  31. package/dist/services/OID4VCIHolderService.d.ts.map +1 -0
  32. package/dist/{agent → services}/OID4VCIHolderService.js +47 -3
  33. package/dist/services/OID4VCIHolderService.js.map +1 -0
  34. package/dist/types/FirstPartyMachine.d.ts +112 -0
  35. package/dist/types/FirstPartyMachine.d.ts.map +1 -0
  36. package/dist/types/FirstPartyMachine.js +30 -0
  37. package/dist/types/FirstPartyMachine.js.map +1 -0
  38. package/dist/types/IOID4VCIHolder.d.ts +26 -15
  39. package/dist/types/IOID4VCIHolder.d.ts.map +1 -1
  40. package/dist/types/IOID4VCIHolder.js +3 -1
  41. package/dist/types/IOID4VCIHolder.js.map +1 -1
  42. package/package.json +25 -21
  43. package/src/agent/OID4VCIHolder.ts +33 -21
  44. package/src/index.ts +5 -2
  45. package/src/link-handler/index.ts +10 -5
  46. package/src/localization/translations/en.json +5 -1
  47. package/src/localization/translations/nl.json +5 -1
  48. package/src/machines/firstPartyMachine.ts +278 -0
  49. package/src/{machine → machines}/oid4vciMachine.ts +62 -3
  50. package/src/{agent → mappers}/OIDC4VCIBrandingMapper.ts +26 -25
  51. package/src/services/FirstPartyMachineServices.ts +64 -0
  52. package/src/{agent → services}/OID4VCIHolderService.ts +56 -9
  53. package/src/types/FirstPartyMachine.ts +161 -0
  54. package/src/types/IOID4VCIHolder.ts +52 -39
  55. package/dist/agent/OID4VCIHolderService.d.ts.map +0 -1
  56. package/dist/agent/OID4VCIHolderService.js.map +0 -1
  57. package/dist/agent/OIDC4VCIBrandingMapper.d.ts.map +0 -1
  58. package/dist/agent/OIDC4VCIBrandingMapper.js.map +0 -1
  59. package/dist/machine/headlessStateNavListener.d.ts.map +0 -1
  60. package/dist/machine/headlessStateNavListener.js.map +0 -1
  61. package/dist/machine/oid4vciMachine.d.ts.map +0 -1
  62. package/dist/machine/oid4vciMachine.js.map +0 -1
  63. /package/dist/{machine → listeners}/headlessStateNavListener.d.ts +0 -0
  64. /package/dist/{machine → listeners}/headlessStateNavListener.js +0 -0
  65. /package/dist/{machine → machines}/oid4vciMachine.d.ts +0 -0
  66. /package/dist/{agent → mappers}/OIDC4VCIBrandingMapper.d.ts +0 -0
  67. /package/src/{machine → listeners}/headlessStateNavListener.ts +0 -0
@@ -0,0 +1,278 @@
1
+ import { assign, createMachine, DoneInvokeEvent, interpret } from 'xstate'
2
+ import { AuthorizationChallengeCodeResponse, AuthorizationChallengeError, AuthorizationChallengeErrorResponse } from '@sphereon/oid4vci-common'
3
+ import { DidAuthConfig } from '@sphereon/ssi-sdk.data-store'
4
+ import { CreateConfigResult } from '@sphereon/ssi-sdk.siopv2-oid4vp-op-auth'
5
+ import { createConfig, getSiopRequest, sendAuthorizationChallengeRequest, sendAuthorizationResponse } from '../services/FirstPartyMachineServices'
6
+ import { translate } from '../localization/Localization'
7
+ import { ErrorDetails } from '../types/IOID4VCIHolder'
8
+ import {
9
+ CreateConfigArgs,
10
+ CreateFirstPartyMachineOpts,
11
+ FirstPartyMachineContext,
12
+ FirstPartyMachineEvents,
13
+ FirstPartyMachineEventTypes,
14
+ FirstPartyMachineInterpreter,
15
+ FirstPartyMachineServices,
16
+ FirstPartyMachineState,
17
+ FirstPartyMachineStatesConfig,
18
+ FirstPartyMachineStateTypes,
19
+ FirstPartyMachineServiceDefinitions,
20
+ FirstPartyStateMachine,
21
+ GetSiopRequestArgs,
22
+ InstanceFirstPartyMachineOpts,
23
+ SiopV2AuthorizationRequestData,
24
+ SendAuthorizationResponseArgs,
25
+ FirstPartySelectCredentialsEvent,
26
+ } from '../types/FirstPartyMachine'
27
+
28
+ const firstPartyMachineStates: FirstPartyMachineStatesConfig = {
29
+ [FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest]: {
30
+ id: FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest,
31
+ invoke: {
32
+ src: FirstPartyMachineServices.sendAuthorizationChallengeRequest,
33
+ onDone: {
34
+ target: FirstPartyMachineStateTypes.done,
35
+ actions: assign({
36
+ authorizationCodeResponse: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeCodeResponse>) => _event.data,
37
+ }),
38
+ },
39
+ onError: [
40
+ {
41
+ target: FirstPartyMachineStateTypes.createConfig,
42
+ cond: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeErrorResponse>): boolean =>
43
+ _event.data.error === AuthorizationChallengeError.insufficient_authorization,
44
+ actions: assign({
45
+ authSession: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeErrorResponse>) => _event.data.auth_session,
46
+ presentationUri: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeErrorResponse>) =>
47
+ _event.data.presentation,
48
+ }),
49
+ },
50
+ {
51
+ target: FirstPartyMachineStateTypes.error,
52
+ actions: assign({
53
+ error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
54
+ title: translate('oid4vci_machine_send_authorization_challenge_request_error_title'),
55
+ message: _event.data.message,
56
+ stack: _event.data.stack,
57
+ }),
58
+ }),
59
+ },
60
+ ],
61
+ },
62
+ },
63
+ [FirstPartyMachineStateTypes.createConfig]: {
64
+ id: FirstPartyMachineStateTypes.createConfig,
65
+ invoke: {
66
+ src: FirstPartyMachineServices.createConfig,
67
+ onDone: {
68
+ target: FirstPartyMachineStateTypes.getSiopRequest,
69
+ actions: assign({
70
+ didAuthConfig: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<DidAuthConfig>) => _event.data,
71
+ }),
72
+ },
73
+ onError: {
74
+ target: FirstPartyMachineStateTypes.error,
75
+ actions: assign({
76
+ error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
77
+ title: translate('oid4vci_machine_create_config_error_title'),
78
+ message: _event.data.message,
79
+ stack: _event.data.stack,
80
+ }),
81
+ }),
82
+ },
83
+ },
84
+ },
85
+ [FirstPartyMachineStateTypes.getSiopRequest]: {
86
+ id: FirstPartyMachineStateTypes.getSiopRequest,
87
+ invoke: {
88
+ src: FirstPartyMachineServices.getSiopRequest,
89
+ onDone: {
90
+ target: FirstPartyMachineStateTypes.selectCredentials,
91
+ actions: assign({
92
+ authorizationRequestData: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<SiopV2AuthorizationRequestData>) => _event.data,
93
+ }),
94
+ },
95
+ onError: {
96
+ target: FirstPartyMachineStateTypes.error,
97
+ actions: assign({
98
+ error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
99
+ title: translate('siopV2_machine_get_request_error_title'),
100
+ message: _event.data.message,
101
+ stack: _event.data.stack,
102
+ }),
103
+ }),
104
+ },
105
+ },
106
+ },
107
+ [FirstPartyMachineStateTypes.selectCredentials]: {
108
+ id: FirstPartyMachineStateTypes.selectCredentials,
109
+ on: {
110
+ [FirstPartyMachineEvents.SET_SELECTED_CREDENTIALS]: {
111
+ actions: assign({ selectedCredentials: (_ctx: FirstPartyMachineContext, _event: FirstPartySelectCredentialsEvent) => _event.data }),
112
+ },
113
+ [FirstPartyMachineEvents.NEXT]: {
114
+ target: FirstPartyMachineStateTypes.sendAuthorizationResponse,
115
+ },
116
+ [FirstPartyMachineEvents.DECLINE]: {
117
+ target: FirstPartyMachineStateTypes.declined,
118
+ },
119
+ [FirstPartyMachineEvents.PREVIOUS]: {
120
+ target: FirstPartyMachineStateTypes.aborted,
121
+ },
122
+ },
123
+ },
124
+ [FirstPartyMachineStateTypes.sendAuthorizationResponse]: {
125
+ id: FirstPartyMachineStateTypes.sendAuthorizationResponse,
126
+ invoke: {
127
+ src: FirstPartyMachineServices.sendAuthorizationResponse,
128
+ onDone: {
129
+ target: FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest,
130
+ actions: assign({
131
+ presentationDuringIssuanceSession: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<string>) => _event.data,
132
+ }),
133
+ },
134
+ onError: {
135
+ target: FirstPartyMachineStateTypes.error,
136
+ actions: assign({
137
+ error: (_ctx: FirstPartyMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
138
+ title: translate('oid4vci_machine_get_request_error_title'),
139
+ message: _event.data.message,
140
+ stack: _event.data.stack,
141
+ }),
142
+ }),
143
+ },
144
+ },
145
+ },
146
+ [FirstPartyMachineStateTypes.aborted]: {
147
+ id: FirstPartyMachineStateTypes.aborted,
148
+ type: 'final',
149
+ },
150
+ [FirstPartyMachineStateTypes.declined]: {
151
+ id: FirstPartyMachineStateTypes.declined,
152
+ type: 'final',
153
+ },
154
+ [FirstPartyMachineStateTypes.error]: {
155
+ id: FirstPartyMachineStateTypes.error,
156
+ type: 'final',
157
+ },
158
+ [FirstPartyMachineStateTypes.done]: {
159
+ id: FirstPartyMachineStateTypes.done,
160
+ type: 'final',
161
+ },
162
+ }
163
+
164
+ const createFirstPartyActivationMachine = (opts: CreateFirstPartyMachineOpts): FirstPartyStateMachine => {
165
+ const initialContext: FirstPartyMachineContext = {
166
+ openID4VCIClientState: opts.openID4VCIClientState,
167
+ contact: opts.contact,
168
+ selectedCredentials: [],
169
+ }
170
+
171
+ return createMachine<FirstPartyMachineContext, FirstPartyMachineEventTypes>({
172
+ id: opts?.machineId ?? 'FirstParty',
173
+ predictableActionArguments: true,
174
+ initial: FirstPartyMachineStateTypes.sendAuthorizationChallengeRequest,
175
+ context: initialContext,
176
+ states: firstPartyMachineStates,
177
+ schema: {
178
+ events: {} as FirstPartyMachineEventTypes,
179
+ services: {} as {
180
+ [FirstPartyMachineServices.sendAuthorizationChallengeRequest]: {
181
+ data: void
182
+ }
183
+ [FirstPartyMachineServices.createConfig]: {
184
+ data: CreateConfigResult
185
+ }
186
+ [FirstPartyMachineServices.getSiopRequest]: {
187
+ data: SiopV2AuthorizationRequestData
188
+ }
189
+ [FirstPartyMachineServices.sendAuthorizationResponse]: {
190
+ data: string
191
+ }
192
+ },
193
+ },
194
+ })
195
+ }
196
+
197
+ export class FirstPartyMachine {
198
+ private static _instance: FirstPartyMachineInterpreter | undefined
199
+
200
+ static hasInstance(): boolean {
201
+ return FirstPartyMachine._instance !== undefined
202
+ }
203
+
204
+ static get instance(): FirstPartyMachineInterpreter {
205
+ if (!FirstPartyMachine._instance) {
206
+ throw Error('Please initialize ESIMActivation machine first')
207
+ }
208
+ return FirstPartyMachine._instance
209
+ }
210
+
211
+ static clearInstance(opts: { stop: boolean }) {
212
+ const { stop } = opts
213
+ if (FirstPartyMachine.hasInstance()) {
214
+ if (stop) {
215
+ FirstPartyMachine.stopInstance()
216
+ }
217
+ }
218
+ FirstPartyMachine._instance = undefined
219
+ }
220
+
221
+ static stopInstance(): void {
222
+ if (!FirstPartyMachine.hasInstance()) {
223
+ return
224
+ }
225
+ FirstPartyMachine.instance.stop()
226
+ FirstPartyMachine._instance = undefined
227
+ }
228
+
229
+ public static newInstance(opts: InstanceFirstPartyMachineOpts): FirstPartyMachineInterpreter {
230
+ const { agentContext } = opts
231
+ const services: FirstPartyMachineServiceDefinitions = {
232
+ [FirstPartyMachineServices.sendAuthorizationChallengeRequest]: sendAuthorizationChallengeRequest,
233
+ [FirstPartyMachineServices.createConfig]: (args: CreateConfigArgs) => createConfig(args, agentContext),
234
+ [FirstPartyMachineServices.getSiopRequest]: (args: GetSiopRequestArgs) => getSiopRequest(args, agentContext),
235
+ [FirstPartyMachineServices.sendAuthorizationResponse]: (args: SendAuthorizationResponseArgs) => sendAuthorizationResponse(args, agentContext),
236
+ }
237
+
238
+ const newInst: FirstPartyMachineInterpreter = interpret(
239
+ createFirstPartyActivationMachine(opts).withConfig({
240
+ services: {
241
+ ...services,
242
+ ...opts?.services,
243
+ },
244
+ guards: {
245
+ ...opts?.guards,
246
+ },
247
+ }),
248
+ )
249
+
250
+ if (typeof opts?.subscription === 'function') {
251
+ newInst.onTransition(opts.subscription)
252
+ }
253
+
254
+ if (opts?.requireCustomNavigationHook !== true) {
255
+ newInst.onTransition((snapshot: FirstPartyMachineState): void => {
256
+ if (opts?.stateNavigationListener) {
257
+ void opts.stateNavigationListener(newInst, snapshot)
258
+ }
259
+ })
260
+ }
261
+
262
+ return newInst
263
+ }
264
+
265
+ static getInstance(
266
+ opts: InstanceFirstPartyMachineOpts & {
267
+ requireExisting?: boolean
268
+ },
269
+ ): FirstPartyMachineInterpreter {
270
+ if (!FirstPartyMachine._instance) {
271
+ if (opts?.requireExisting === true) {
272
+ throw Error(`Existing FirstPartyMachine instance requested, but none was created at this point!`)
273
+ }
274
+ FirstPartyMachine._instance = FirstPartyMachine.newInstance(opts)
275
+ }
276
+ return FirstPartyMachine._instance
277
+ }
278
+ }
@@ -1,4 +1,4 @@
1
- import { AuthzFlowType, toAuthorizationResponsePayload } from '@sphereon/oid4vci-common'
1
+ import { AuthorizationChallengeCodeResponse, AuthzFlowType, toAuthorizationResponsePayload } from '@sphereon/oid4vci-common'
2
2
  import { IBasicIssuerLocaleBranding, Identity, IIssuerLocaleBranding, Party } from '@sphereon/ssi-sdk.data-store'
3
3
  import { assign, createMachine, DoneInvokeEvent, interpret } from 'xstate'
4
4
  import { translate } from '../localization/Localization'
@@ -29,6 +29,7 @@ import {
29
29
  SetAuthorizationCodeURLEvent,
30
30
  VerificationCodeEvent,
31
31
  } from '../types/IOID4VCIHolder'
32
+ import { FirstPartyMachineStateTypes } from '../types/FirstPartyMachine'
32
33
 
33
34
  const oid4vciHasNoContactGuard = (_ctx: OID4VCIMachineContext, _event: OID4VCIMachineEventTypes): boolean => {
34
35
  const { contact } = _ctx
@@ -117,6 +118,10 @@ const oid4vciHasAuthorizationResponse = (ctx: OID4VCIMachineContext, _event: OID
117
118
  return !!ctx.openID4VCIClientState?.authorizationCodeResponse
118
119
  }
119
120
 
121
+ const oid4vciIsFirstPartyApplication = (ctx: OID4VCIMachineContext, _event: OID4VCIMachineEventTypes): boolean => {
122
+ return !!ctx.serverMetadata?.authorization_challenge_endpoint
123
+ }
124
+
120
125
  const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMachine => {
121
126
  const initialContext: OID4VCIMachineContext = {
122
127
  // TODO WAL-671 we need to store the data from OpenIdProvider here in the context and make sure we can restart the machine with it and init the OpenIdProvider
@@ -153,7 +158,8 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
153
158
  | { type: OID4VCIMachineGuards.hasSelectedCredentialsGuard }
154
159
  | { type: OID4VCIMachineGuards.hasAuthorizationResponse }
155
160
  | { type: OID4VCIMachineGuards.isOIDFOriginGuard }
156
- | { type: OID4VCIMachineGuards.contactHasLowTrustGuard },
161
+ | { type: OID4VCIMachineGuards.contactHasLowTrustGuard }
162
+ | { type: OID4VCIMachineGuards.isFirstPartyApplication },
157
163
  services: {} as {
158
164
  [OID4VCIMachineServices.start]: {
159
165
  data: StartResult
@@ -188,6 +194,9 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
188
194
  [OID4VCIMachineServices.getIssuerBranding]: {
189
195
  data: Array<IIssuerLocaleBranding | IBasicIssuerLocaleBranding>
190
196
  }
197
+ [OID4VCIMachineServices.startFirstPartApplicationFlow]: {
198
+ data: void
199
+ }
191
200
  },
192
201
  },
193
202
  context: initialContext,
@@ -332,6 +341,10 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
332
341
  target: OID4VCIMachineStates.selectCredentials,
333
342
  cond: OID4VCIMachineGuards.credentialsToSelectRequiredGuard,
334
343
  },
344
+ {
345
+ target: OID4VCIMachineStates.startFirstPartApplicationFlow,
346
+ cond: OID4VCIMachineGuards.isFirstPartyApplication,
347
+ },
335
348
  {
336
349
  target: OID4VCIMachineStates.initiateAuthorizationRequest,
337
350
  cond: OID4VCIMachineGuards.requireAuthorizationGuard,
@@ -422,6 +435,10 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
422
435
  target: OID4VCIMachineStates.selectCredentials,
423
436
  cond: OID4VCIMachineGuards.credentialsToSelectRequiredGuard,
424
437
  },
438
+ {
439
+ target: OID4VCIMachineStates.startFirstPartApplicationFlow,
440
+ cond: OID4VCIMachineGuards.isFirstPartyApplication,
441
+ },
425
442
  {
426
443
  target: OID4VCIMachineStates.initiateAuthorizationRequest,
427
444
  cond: OID4VCIMachineGuards.requireAuthorizationGuard,
@@ -435,6 +452,43 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
435
452
  },
436
453
  ],
437
454
  },
455
+ [OID4VCIMachineStates.startFirstPartApplicationFlow]: {
456
+ id: OID4VCIMachineStates.startFirstPartApplicationFlow,
457
+ invoke: {
458
+ src: OID4VCIMachineServices.startFirstPartApplicationFlow,
459
+ onDone: [
460
+ {
461
+ target: OID4VCIMachineStates.aborted,
462
+ cond: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<FirstPartyMachineStateTypes>): boolean =>
463
+ _event.data === FirstPartyMachineStateTypes.aborted,
464
+ },
465
+ {
466
+ target: OID4VCIMachineStates.declined,
467
+ cond: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<FirstPartyMachineStateTypes>): boolean =>
468
+ _event.data === FirstPartyMachineStateTypes.declined,
469
+ },
470
+ {
471
+ target: OID4VCIMachineStates.getCredentials,
472
+ actions: assign({
473
+ openID4VCIClientState: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<AuthorizationChallengeCodeResponse>) => {
474
+ const authorizationCodeResponse = toAuthorizationResponsePayload(_event.data)
475
+ return { ..._ctx.openID4VCIClientState!, authorizationCodeResponse }
476
+ },
477
+ }),
478
+ },
479
+ ],
480
+ onError: {
481
+ target: OID4VCIMachineStates.handleError,
482
+ actions: assign({
483
+ error: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<ErrorDetails>): ErrorDetails => ({
484
+ title: _event.data.title ?? translate('oid4vci_machine_first_party_error_title'),
485
+ message: _event.data.message,
486
+ stack: _event.data.stack,
487
+ }),
488
+ }),
489
+ },
490
+ },
491
+ },
438
492
  [OID4VCIMachineStates.selectCredentials]: {
439
493
  id: OID4VCIMachineStates.selectCredentials,
440
494
  on: {
@@ -453,6 +507,10 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
453
507
  [OID4VCIMachineStates.transitionFromSelectingCredentials]: {
454
508
  id: OID4VCIMachineStates.transitionFromSelectingCredentials,
455
509
  always: [
510
+ {
511
+ target: OID4VCIMachineStates.startFirstPartApplicationFlow,
512
+ cond: OID4VCIMachineGuards.isFirstPartyApplication,
513
+ },
456
514
  {
457
515
  target: OID4VCIMachineStates.verifyPin,
458
516
  cond: OID4VCIMachineGuards.requirePinGuard,
@@ -726,6 +784,7 @@ export class OID4VCIMachine {
726
784
  oid4vciHasAuthorizationResponse,
727
785
  oid4vciIsOIDFOriginGuard,
728
786
  oid4vciContactHasLowTrustGuard,
787
+ oid4vciIsFirstPartyApplication,
729
788
  ...opts?.guards,
730
789
  },
731
790
  }),
@@ -737,7 +796,7 @@ export class OID4VCIMachine {
737
796
  if (opts?.requireCustomNavigationHook !== true) {
738
797
  if (typeof opts?.stateNavigationListener === 'function') {
739
798
  interpreter.onTransition((snapshot: OID4VCIMachineState): void => {
740
- if (opts?.stateNavigationListener !== undefined) {
799
+ if (opts?.stateNavigationListener) {
741
800
  opts.stateNavigationListener(interpreter, snapshot)
742
801
  }
743
802
  })
@@ -1,15 +1,6 @@
1
1
  import { CredentialsSupportedDisplay, NameAndLocale } from '@sphereon/oid4vci-common'
2
- import {
3
- IBasicCredentialClaim,
4
- IBasicCredentialLocaleBranding,
5
- IBasicIssuerLocaleBranding
6
- } from '@sphereon/ssi-sdk.data-store'
7
- import {
8
- SdJwtClaimDisplayMetadata,
9
- SdJwtClaimMetadata,
10
- SdJwtClaimPath,
11
- SdJwtTypeDisplayMetadata
12
- } from '@sphereon/ssi-types'
2
+ import { IBasicCredentialClaim, IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding } from '@sphereon/ssi-sdk.data-store'
3
+ import { SdJwtClaimDisplayMetadata, SdJwtClaimMetadata, SdJwtClaimPath, SdJwtTypeDisplayMetadata } from '@sphereon/ssi-types'
13
4
  import {
14
5
  IssuerLocaleBrandingFromArgs,
15
6
  Oid4vciCombineDisplayLocalesFromArgs,
@@ -26,7 +17,9 @@ import {
26
17
 
27
18
  // FIXME should we not move this to the branding plugin?
28
19
 
29
- export const oid4vciGetCredentialBrandingFrom = async (args: Oid4vciGetCredentialBrandingFromArgs): Promise<Array<IBasicCredentialLocaleBranding>> => {
20
+ export const oid4vciGetCredentialBrandingFrom = async (
21
+ args: Oid4vciGetCredentialBrandingFromArgs,
22
+ ): Promise<Array<IBasicCredentialLocaleBranding>> => {
30
23
  const { credentialDisplay, issuerCredentialSubject } = args
31
24
 
32
25
  return oid4vciCombineDisplayLocalesFrom({
@@ -35,7 +28,9 @@ export const oid4vciGetCredentialBrandingFrom = async (args: Oid4vciGetCredentia
35
28
  })
36
29
  }
37
30
 
38
- export const oid4vciCredentialDisplayLocalesFrom = async (args: Oid4vciCredentialDisplayLocalesFromArgs): Promise<Map<string, CredentialsSupportedDisplay>> => {
31
+ export const oid4vciCredentialDisplayLocalesFrom = async (
32
+ args: Oid4vciCredentialDisplayLocalesFromArgs,
33
+ ): Promise<Map<string, CredentialsSupportedDisplay>> => {
39
34
  const { credentialDisplay } = args
40
35
  return credentialDisplay.reduce((localeDisplays, display) => {
41
36
  const localeKey = display.locale || ''
@@ -44,7 +39,9 @@ export const oid4vciCredentialDisplayLocalesFrom = async (args: Oid4vciCredentia
44
39
  }, new Map<string, CredentialsSupportedDisplay>())
45
40
  }
46
41
 
47
- export const oid4vciIssuerCredentialSubjectLocalesFrom = async (args: Oid4vciIssuerCredentialSubjectLocalesFromArgs): Promise<Map<string, Array<IBasicCredentialClaim>>> => {
42
+ export const oid4vciIssuerCredentialSubjectLocalesFrom = async (
43
+ args: Oid4vciIssuerCredentialSubjectLocalesFromArgs,
44
+ ): Promise<Map<string, Array<IBasicCredentialClaim>>> => {
48
45
  const { issuerCredentialSubject } = args
49
46
  const localeClaims = new Map<string, Array<IBasicCredentialClaim>>()
50
47
 
@@ -125,7 +122,9 @@ export const oid4vciCredentialLocaleBrandingFrom = async (args: Oid4vciCredentia
125
122
  }
126
123
  }
127
124
 
128
- export const oid4vciCombineDisplayLocalesFrom = async (args: Oid4vciCombineDisplayLocalesFromArgs): Promise<Array<IBasicCredentialLocaleBranding>> => {
125
+ export const oid4vciCombineDisplayLocalesFrom = async (
126
+ args: Oid4vciCombineDisplayLocalesFromArgs,
127
+ ): Promise<Array<IBasicCredentialLocaleBranding>> => {
129
128
  const {
130
129
  credentialDisplayLocales = new Map<string, CredentialsSupportedDisplay>(),
131
130
  issuerCredentialSubjectLocales = new Map<string, Array<IBasicCredentialClaim>>(),
@@ -156,7 +155,9 @@ export const sdJwtGetCredentialBrandingFrom = async (args: SdJwtGetCredentialBra
156
155
  })
157
156
  }
158
157
 
159
- export const sdJwtCredentialDisplayLocalesFrom = async (args: SdJwtCredentialDisplayLocalesFromArgs): Promise<Map<string, SdJwtTypeDisplayMetadata>> => {
158
+ export const sdJwtCredentialDisplayLocalesFrom = async (
159
+ args: SdJwtCredentialDisplayLocalesFromArgs,
160
+ ): Promise<Map<string, SdJwtTypeDisplayMetadata>> => {
160
161
  const { credentialDisplay } = args
161
162
  return credentialDisplay.reduce((localeDisplays, display) => {
162
163
  const localeKey = display.lang || ''
@@ -165,14 +166,16 @@ export const sdJwtCredentialDisplayLocalesFrom = async (args: SdJwtCredentialDis
165
166
  }, new Map<string, SdJwtTypeDisplayMetadata>())
166
167
  }
167
168
 
168
- export const sdJwtCredentialClaimLocalesFrom = async (args: SdJwtCredentialClaimLocalesFromArgs): Promise<Map<string, Array<IBasicCredentialClaim>>> => {
169
+ export const sdJwtCredentialClaimLocalesFrom = async (
170
+ args: SdJwtCredentialClaimLocalesFromArgs,
171
+ ): Promise<Map<string, Array<IBasicCredentialClaim>>> => {
169
172
  const { claimsMetadata } = args
170
173
  const localeClaims = new Map<string, Array<IBasicCredentialClaim>>()
171
174
 
172
175
  claimsMetadata.forEach((claim: SdJwtClaimMetadata): void => {
173
176
  claim.display?.forEach((display: SdJwtClaimDisplayMetadata): void => {
174
- const { lang = '', label } = display;
175
- const key = claim.path.map((value: SdJwtClaimPath) => String(value)).join('.');
177
+ const { lang = '', label } = display
178
+ const key = claim.path.map((value: SdJwtClaimPath) => String(value)).join('.')
176
179
  if (!localeClaims.has(lang)) {
177
180
  localeClaims.set(lang, [])
178
181
  }
@@ -180,7 +183,7 @@ export const sdJwtCredentialClaimLocalesFrom = async (args: SdJwtCredentialClaim
180
183
  })
181
184
  })
182
185
 
183
- return localeClaims;
186
+ return localeClaims
184
187
  }
185
188
 
186
189
  export const sdJwtCredentialLocaleBrandingFrom = async (args: SdJwtCredentialLocaleBrandingFromArgs): Promise<IBasicCredentialLocaleBranding> => {
@@ -213,17 +216,15 @@ export const sdJwtCredentialLocaleBrandingFrom = async (args: SdJwtCredentialLoc
213
216
  }),
214
217
  ...(credentialDisplay.rendering?.simple?.background_color && {
215
218
  background: {
216
- color: credentialDisplay.rendering.simple.background_color ,
219
+ color: credentialDisplay.rendering.simple.background_color,
217
220
  },
218
221
  }),
219
222
  }
220
223
  }
221
224
 
222
225
  export const sdJwtCombineDisplayLocalesFrom = async (args: SdJwtCombineDisplayLocalesFromArgs): Promise<Array<IBasicCredentialLocaleBranding>> => {
223
- const {
224
- credentialDisplayLocales = new Map<string, SdJwtTypeDisplayMetadata>(),
225
- claimsMetadata = new Map<string, Array<IBasicCredentialClaim>>(),
226
- } = args
226
+ const { credentialDisplayLocales = new Map<string, SdJwtTypeDisplayMetadata>(), claimsMetadata = new Map<string, Array<IBasicCredentialClaim>>() } =
227
+ args
227
228
 
228
229
  const locales: Array<string> = Array.from(new Set([...claimsMetadata.keys(), ...credentialDisplayLocales.keys()]))
229
230
 
@@ -0,0 +1,64 @@
1
+ import { OpenID4VCIClient } from '@sphereon/oid4vci-client'
2
+ import { AuthorizationChallengeValidationResponse } from '@sphereon/ssi-sdk.siopv2-oid4vp-common'
3
+ import { AuthorizationChallengeCodeResponse } from '@sphereon/oid4vci-common'
4
+ import { CreateConfigResult } from '@sphereon/ssi-sdk.siopv2-oid4vp-op-auth'
5
+ import { v4 as uuidv4 } from 'uuid'
6
+ import { RequiredContext } from '../types/IOID4VCIHolder'
7
+ import {
8
+ CreateConfigArgs,
9
+ GetSiopRequestArgs,
10
+ SendAuthorizationChallengeRequestArgs,
11
+ SendAuthorizationResponseArgs,
12
+ SiopV2AuthorizationRequestData,
13
+ } from '../types/FirstPartyMachine'
14
+
15
+ export const sendAuthorizationChallengeRequest = async (args: SendAuthorizationChallengeRequestArgs): Promise<AuthorizationChallengeCodeResponse> => {
16
+ const { openID4VCIClientState, authSession, presentationDuringIssuanceSession } = args
17
+
18
+ const oid4vciClient = await OpenID4VCIClient.fromState({ state: openID4VCIClientState })
19
+ return oid4vciClient.acquireAuthorizationChallengeCode({
20
+ clientId: oid4vciClient.clientId ?? uuidv4(),
21
+ ...(authSession && { authSession }),
22
+ ...(!authSession &&
23
+ openID4VCIClientState.credentialOffer?.preAuthorizedCode && { issuerState: openID4VCIClientState.credentialOffer?.preAuthorizedCode }),
24
+ ...(!authSession && openID4VCIClientState.credentialOffer?.issuerState && { issuerState: openID4VCIClientState.credentialOffer?.issuerState }),
25
+ ...(presentationDuringIssuanceSession && { presentationDuringIssuanceSession }),
26
+ })
27
+ }
28
+
29
+ export const createConfig = async (args: CreateConfigArgs, context: RequiredContext): Promise<CreateConfigResult> => {
30
+ const { presentationUri } = args
31
+
32
+ if (!presentationUri) {
33
+ return Promise.reject(Error('Missing presentation uri in context'))
34
+ }
35
+
36
+ return context.agent.siopCreateConfig({ url: presentationUri })
37
+ }
38
+
39
+ export const getSiopRequest = async (args: GetSiopRequestArgs, context: RequiredContext): Promise<SiopV2AuthorizationRequestData> => {
40
+ const { didAuthConfig, presentationUri } = args
41
+
42
+ if (presentationUri === undefined) {
43
+ return Promise.reject(Error('Missing presentation uri in context'))
44
+ }
45
+
46
+ if (didAuthConfig === undefined) {
47
+ return Promise.reject(Error('Missing did auth config in context'))
48
+ }
49
+
50
+ return context.agent.siopGetSiopRequest({ didAuthConfig, url: presentationUri })
51
+ }
52
+
53
+ export const sendAuthorizationResponse = async (args: SendAuthorizationResponseArgs, context: RequiredContext): Promise<string> => {
54
+ const { didAuthConfig, authorizationRequestData, selectedCredentials } = args
55
+
56
+ const responseData = await context.agent.siopSendResponse({
57
+ authorizationRequestData,
58
+ selectedCredentials,
59
+ didAuthConfig,
60
+ isFirstParty: true,
61
+ })
62
+
63
+ return (<AuthorizationChallengeValidationResponse>responseData.body).presentation_during_issuance_session
64
+ }