@sphereon/ssi-sdk.oid4vci-holder 0.32.1-feature.MWALL.715.49 → 0.32.1-feature.SDK.56.oauth.status.list.139

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