@sphereon/ssi-sdk.oid4vci-holder 0.32.1-next.13 → 0.32.1-next.141

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 (68) hide show
  1. package/dist/agent/OID4VCIHolder.d.ts +1 -0
  2. package/dist/agent/OID4VCIHolder.d.ts.map +1 -1
  3. package/dist/agent/OID4VCIHolder.js +24 -16
  4. package/dist/agent/OID4VCIHolder.js.map +1 -1
  5. package/dist/index.d.ts +4 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +4 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/link-handler/index.d.ts +3 -2
  10. package/dist/link-handler/index.d.ts.map +1 -1
  11. package/dist/link-handler/index.js +2 -1
  12. package/dist/link-handler/index.js.map +1 -1
  13. package/dist/listeners/headlessStateNavListener.d.ts.map +1 -0
  14. package/dist/listeners/headlessStateNavListener.js.map +1 -0
  15. package/dist/localization/translations/en.json +5 -1
  16. package/dist/localization/translations/nl.json +5 -1
  17. package/dist/machines/firstPartyMachine.d.ts +15 -0
  18. package/dist/machines/firstPartyMachine.d.ts.map +1 -0
  19. package/dist/machines/firstPartyMachine.js +222 -0
  20. package/dist/machines/firstPartyMachine.js.map +1 -0
  21. package/dist/machines/oid4vciMachine.d.ts.map +1 -0
  22. package/dist/{machine → machines}/oid4vciMachine.js +58 -2
  23. package/dist/machines/oid4vciMachine.js.map +1 -0
  24. package/dist/mappers/OIDC4VCIBrandingMapper.d.ts.map +1 -0
  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 +46 -2
  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 +19 -16
  43. package/src/agent/OID4VCIHolder.ts +35 -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/services/FirstPartyMachineServices.ts +63 -0
  51. package/src/{agent → services}/OID4VCIHolderService.ts +48 -1
  52. package/src/types/FirstPartyMachine.ts +169 -0
  53. package/src/types/IOID4VCIHolder.ts +40 -30
  54. package/dist/agent/OID4VCIHolderService.d.ts.map +0 -1
  55. package/dist/agent/OID4VCIHolderService.js.map +0 -1
  56. package/dist/agent/OIDC4VCIBrandingMapper.d.ts.map +0 -1
  57. package/dist/agent/OIDC4VCIBrandingMapper.js.map +0 -1
  58. package/dist/machine/headlessStateNavListener.d.ts.map +0 -1
  59. package/dist/machine/headlessStateNavListener.js.map +0 -1
  60. package/dist/machine/oid4vciMachine.d.ts.map +0 -1
  61. package/dist/machine/oid4vciMachine.js.map +0 -1
  62. /package/dist/{machine → listeners}/headlessStateNavListener.d.ts +0 -0
  63. /package/dist/{machine → listeners}/headlessStateNavListener.js +0 -0
  64. /package/dist/{machine → machines}/oid4vciMachine.d.ts +0 -0
  65. /package/dist/{agent → mappers}/OIDC4VCIBrandingMapper.d.ts +0 -0
  66. /package/dist/{agent → mappers}/OIDC4VCIBrandingMapper.js +0 -0
  67. /package/src/{machine → listeners}/headlessStateNavListener.ts +0 -0
  68. /package/src/{agent → mappers}/OIDC4VCIBrandingMapper.ts +0 -0
@@ -4,6 +4,8 @@ import {
4
4
  AuthorizationRequestOpts,
5
5
  AuthorizationServerClientOpts,
6
6
  AuthorizationServerOpts,
7
+ CredentialConfigurationSupportedJwtVcJsonLdAndLdpVcV1_0_13,
8
+ CredentialDefinitionJwtVcJsonLdAndLdpVcV1_0_13,
7
9
  CredentialOfferRequestWithBaseUrl,
8
10
  DefaultURISchemes,
9
11
  EndpointMetadataResult,
@@ -70,12 +72,12 @@ import {
70
72
  import { asArray, computeEntryHash } from '@veramo/utils'
71
73
  import { decodeJWT } from 'did-jwt'
72
74
  import { v4 as uuidv4 } from 'uuid'
73
- import { OID4VCIMachine } from '../machine/oid4vciMachine'
75
+ import { OID4VCIMachine } from '../machines/oid4vciMachine'
74
76
  import {
75
77
  AddContactIdentityArgs,
76
78
  AssertValidCredentialsArgs,
77
79
  Attribute,
78
- createCredentialsToSelectFromArgs,
80
+ CreateCredentialsToSelectFromArgs,
79
81
  CredentialToAccept,
80
82
  CredentialToSelectFromResult,
81
83
  GetContactArgs,
@@ -91,6 +93,8 @@ import {
91
93
  OID4VCIHolderOptions,
92
94
  OID4VCIMachine as OID4VCIMachineId,
93
95
  OID4VCIMachineInstanceOpts,
96
+ OID4VCIMachineServiceDefinitions,
97
+ OID4VCIMachineServices,
94
98
  OnContactIdentityCreatedArgs,
95
99
  OnCredentialStoredArgs,
96
100
  OnIdentifierCreatedArgs,
@@ -98,13 +102,14 @@ import {
98
102
  RequestType,
99
103
  RequiredContext,
100
104
  SendNotificationArgs,
105
+ StartFirstPartApplicationMachine,
101
106
  StartResult,
102
107
  StoreCredentialBrandingArgs,
103
108
  StoreCredentialsArgs,
104
109
  StoreIssuerBrandingArgs,
105
110
  VerificationResult,
106
111
  VerifyEBSICredentialIssuerArgs,
107
- VerifyEBSICredentialIssuerResult,
112
+ VerifyEBSICredentialIssuerResult
108
113
  } from '../types/IOID4VCIHolder'
109
114
  import {
110
115
  getBasicIssuerLocaleBranding,
@@ -115,8 +120,8 @@ import {
115
120
  mapCredentialToAccept,
116
121
  selectCredentialLocaleBranding,
117
122
  verifyCredentialToAccept,
118
- } from './OID4VCIHolderService'
119
-
123
+ startFirstPartApplicationMachine
124
+ } from '../services/OID4VCIHolderService'
120
125
  import 'cross-fetch/polyfill'
121
126
 
122
127
  /**
@@ -307,8 +312,8 @@ export class OID4VCIHolder implements IAgentPlugin {
307
312
  */
308
313
  private async oid4vciHolderGetMachineInterpreter(opts: OID4VCIMachineInstanceOpts, context: RequiredContext): Promise<OID4VCIMachineId> {
309
314
  const authorizationRequestOpts = { ...this.defaultAuthorizationRequestOpts, ...opts.authorizationRequestOpts }
310
- const services = {
311
- start: (args: PrepareStartArgs) =>
315
+ const services: OID4VCIMachineServiceDefinitions = {
316
+ [OID4VCIMachineServices.start]: (args: PrepareStartArgs) =>
312
317
  this.oid4vciHolderStart(
313
318
  {
314
319
  ...args,
@@ -316,18 +321,18 @@ export class OID4VCIHolder implements IAgentPlugin {
316
321
  },
317
322
  context,
318
323
  ),
319
- createCredentialsToSelectFrom: (args: createCredentialsToSelectFromArgs) => this.oid4vciHolderCreateCredentialsToSelectFrom(args, context),
320
- getContact: (args: GetContactArgs) => this.oid4vciHolderGetContact(args, context),
321
- getCredentials: (args: GetCredentialsArgs) =>
322
- this.oid4vciHolderGetCredentials({ accessTokenOpts: args.accessTokenOpts ?? opts.accessTokenOpts, ...args }, context),
323
- addContactIdentity: (args: AddContactIdentityArgs) => this.oid4vciHolderAddContactIdentity(args, context),
324
- getIssuerBranding: (args: GetIssuerBrandingArgs) => this.oid4vciHolderGetIssuerBranding(args, context),
325
- storeIssuerBranding: (args: StoreIssuerBrandingArgs) => this.oid4vciHolderStoreIssuerBranding(args, context),
326
- assertValidCredentials: (args: AssertValidCredentialsArgs) => this.oid4vciHolderAssertValidCredentials(args, context),
327
- storeCredentialBranding: (args: StoreCredentialBrandingArgs) => this.oid4vciHolderStoreCredentialBranding(args, context),
328
- storeCredentials: (args: StoreCredentialsArgs) => this.oid4vciHolderStoreCredentials(args, context),
329
- sendNotification: (args: SendNotificationArgs) => this.oid4vciHolderSendNotification(args, context),
330
- getFederationTrust: (args: GetFederationTrustArgs) => this.getFederationTrust(args, context),
324
+ [OID4VCIMachineServices.startFirstPartApplicationFlow]: (args: StartFirstPartApplicationMachine) => startFirstPartApplicationMachine({ ...args, stateNavigationListener: opts.firstPartyStateNavigationListener }, context),
325
+ [OID4VCIMachineServices.createCredentialsToSelectFrom]: (args: CreateCredentialsToSelectFromArgs) => this.oid4vciHolderCreateCredentialsToSelectFrom(args, context),
326
+ [OID4VCIMachineServices.getContact]: (args: GetContactArgs) => this.oid4vciHolderGetContact(args, context),
327
+ [OID4VCIMachineServices.getCredentials]: (args: GetCredentialsArgs) => this.oid4vciHolderGetCredentials({ accessTokenOpts: args.accessTokenOpts ?? opts.accessTokenOpts, ...args }, context),
328
+ [OID4VCIMachineServices.addContactIdentity]: (args: AddContactIdentityArgs) => this.oid4vciHolderAddContactIdentity(args, context),
329
+ [OID4VCIMachineServices.getIssuerBranding]: (args: GetIssuerBrandingArgs) => this.oid4vciHolderGetIssuerBranding(args, context),
330
+ [OID4VCIMachineServices.storeIssuerBranding]: (args: StoreIssuerBrandingArgs) => this.oid4vciHolderStoreIssuerBranding(args, context),
331
+ [OID4VCIMachineServices.assertValidCredentials]: (args: AssertValidCredentialsArgs) => this.oid4vciHolderAssertValidCredentials(args, context),
332
+ [OID4VCIMachineServices.storeCredentialBranding]: (args: StoreCredentialBrandingArgs) => this.oid4vciHolderStoreCredentialBranding(args, context),
333
+ [OID4VCIMachineServices.storeCredentials]: (args: StoreCredentialsArgs) => this.oid4vciHolderStoreCredentials(args, context),
334
+ [OID4VCIMachineServices.sendNotification]: (args: SendNotificationArgs) => this.oid4vciHolderSendNotification(args, context),
335
+ [OID4VCIMachineServices.getFederationTrust]: (args: GetFederationTrustArgs) => this.getFederationTrust(args, context),
331
336
  }
332
337
 
333
338
  const oid4vciMachineInstanceArgs: OID4VCIMachineInstanceOpts = {
@@ -463,7 +468,7 @@ export class OID4VCIHolder implements IAgentPlugin {
463
468
  }
464
469
 
465
470
  private async oid4vciHolderCreateCredentialsToSelectFrom(
466
- args: createCredentialsToSelectFromArgs,
471
+ args: CreateCredentialsToSelectFromArgs,
467
472
  context: RequiredContext,
468
473
  ): Promise<Array<CredentialToSelectFromResult>> {
469
474
  const { credentialBranding, locale, selectedCredentials /*, openID4VCIClientState*/, credentialsSupported } = args
@@ -675,7 +680,10 @@ export class OID4VCIHolder implements IAgentPlugin {
675
680
  if (!credentialTypes || credentialTypes.length === 0) {
676
681
  return Promise.reject(Error('cannot determine credential id to request'))
677
682
  }
683
+
684
+ const credentialDefinition = this.getCredentialDefinition(issuanceOpt)
678
685
  const credentialResponse = await client.acquireCredentials({
686
+ ...(credentialDefinition && { context: credentialDefinition['@context'] }),
679
687
  credentialTypes,
680
688
  proofCallbacks: callbacks,
681
689
  format: issuanceOpt.format,
@@ -1127,4 +1135,11 @@ export class OID4VCIHolder implements IAgentPlugin {
1127
1135
  }
1128
1136
  return undefined
1129
1137
  }
1138
+
1139
+ private getCredentialDefinition(issuanceOpt: IssuanceOpts): CredentialDefinitionJwtVcJsonLdAndLdpVcV1_0_13 | undefined {
1140
+ if (issuanceOpt.format == 'ldp_vc' || issuanceOpt.format == 'jwt_vc_json-ld') {
1141
+ return (issuanceOpt as CredentialConfigurationSupportedJwtVcJsonLdAndLdpVcV1_0_13).credential_definition
1142
+ }
1143
+ return undefined
1144
+ }
1130
1145
  }
package/src/index.ts CHANGED
@@ -3,7 +3,9 @@
3
3
  */
4
4
 
5
5
  export { OID4VCIHolder, oid4vciHolderContextMethods, signCallback } from './agent/OID4VCIHolder'
6
- export * from './agent/OID4VCIHolderService'
6
+ export * from './services/OID4VCIHolderService'
7
+ export * from './services/FirstPartyMachineServices'
7
8
  export * from './types/IOID4VCIHolder'
8
- export * from './machine/headlessStateNavListener'
9
+ export * from './types/FirstPartyMachine'
10
+ export * from './listeners/headlessStateNavListener'
9
11
  export * from './link-handler'
@@ -3,23 +3,28 @@ import { AuthorizationRequestOpts, AuthorizationServerClientOpts, AuthzFlowType,
3
3
  import { DefaultLinkPriorities, LinkHandlerAdapter } from '@sphereon/ssi-sdk.core'
4
4
  import { IMachineStatePersistence, interpreterStartOrResume, SerializableState } from '@sphereon/ssi-sdk.xstate-machine-persistence'
5
5
  import { IAgentContext } from '@veramo/core'
6
- import { GetMachineArgs, IOID4VCIHolder, OID4VCIMachineEvents, OID4VCIMachineInterpreter, OID4VCIMachineState } from '../types/IOID4VCIHolder'
6
+ import {
7
+ GetMachineArgs,
8
+ IOID4VCIHolder,
9
+ OID4VCIMachineEvents,
10
+ OID4VCIMachineStateNavigationListener
11
+ } from '../types/IOID4VCIHolder'
12
+ import { FirstPartyMachineStateNavigationListener } from '../types/FirstPartyMachine'
7
13
 
8
14
  /**
9
15
  * This handler only handles credential offer links (either by value or by reference)
10
16
  */
11
17
  export class OID4VCIHolderLinkHandler extends LinkHandlerAdapter {
12
18
  private readonly context: IAgentContext<IOID4VCIHolder & IMachineStatePersistence>
13
- private readonly stateNavigationListener:
14
- | ((oid4vciMachine: OID4VCIMachineInterpreter, state: OID4VCIMachineState, navigation?: any) => Promise<void>)
15
- | undefined
19
+ private readonly stateNavigationListener?: OID4VCIMachineStateNavigationListener
20
+ private readonly firstPartyStateNavigationListener?: FirstPartyMachineStateNavigationListener
16
21
  private readonly noStateMachinePersistence: boolean
17
22
  private readonly authorizationRequestOpts?: AuthorizationRequestOpts
18
23
  private readonly clientOpts?: AuthorizationServerClientOpts
19
24
  private readonly trustAnchors?: Array<string>
20
25
 
21
26
  constructor(
22
- args: Pick<GetMachineArgs, 'stateNavigationListener' | 'authorizationRequestOpts' | 'clientOpts' | 'trustAnchors'> & {
27
+ args: Pick<GetMachineArgs, 'stateNavigationListener' | 'authorizationRequestOpts' | 'clientOpts' | 'trustAnchors' | 'firstPartyStateNavigationListener'> & {
23
28
  priority?: number | DefaultLinkPriorities
24
29
  protocols?: Array<string | RegExp>
25
30
  noStateMachinePersistence?: boolean
@@ -32,6 +37,7 @@ export class OID4VCIHolderLinkHandler extends LinkHandlerAdapter {
32
37
  this.context = args.context
33
38
  this.noStateMachinePersistence = args.noStateMachinePersistence === true
34
39
  this.stateNavigationListener = args.stateNavigationListener
40
+ this.firstPartyStateNavigationListener = args.firstPartyStateNavigationListener
35
41
  this.trustAnchors = args.trustAnchors
36
42
  }
37
43
 
@@ -63,6 +69,7 @@ export class OID4VCIHolderLinkHandler extends LinkHandlerAdapter {
63
69
  authorizationRequestOpts: { ...this.authorizationRequestOpts, ...opts?.authorizationRequestOpts },
64
70
  ...((clientOpts.clientId || clientOpts.clientAssertionType) && { clientOpts: clientOpts as AuthorizationServerClientOpts }),
65
71
  stateNavigationListener: this.stateNavigationListener,
72
+ firstPartyStateNavigationListener: this.firstPartyStateNavigationListener
66
73
  })
67
74
 
68
75
  const interpreter = oid4vciMachine.interpreter
@@ -11,5 +11,9 @@
11
11
  "oid4vci_machine_initiation_error_title": "Initiate OID4VCI provider",
12
12
  "oid4vci_machine_credential_verification_failed_message": "The credential verification resulted in an error.",
13
13
  "oid4vci_machine_credential_verification_schema_failed_message": "The credential schema verification resulted in an error.",
14
- "oid4vci_machine_retrieve_federation_trust_error_title": "Retrieve federation trust"
14
+ "oid4vci_machine_retrieve_federation_trust_error_title": "Retrieve federation trust",
15
+ "oid4vci_machine_first_party_error_title": "First party flow",
16
+ "oid4vci_machine_send_authorization_challenge_request_error_title": "Sending authorization challenge request",
17
+ "oid4vci_machine_create_config_error_title": "Creating siopV2 config",
18
+ "oid4vci_machine_get_request_error_title": "Getting siopV2 request"
15
19
  }
@@ -10,5 +10,9 @@
10
10
  "oid4vci_machine_credential_selection_error_title": "Credential selectie",
11
11
  "oid4vci_machine_initiation_error_title": "Initiëren OID4VCI provider",
12
12
  "oid4vci_machine_credential_verification_failed_message": "Verificatie van de credential leidde tot een fout.",
13
- "oid4vci_machine_retrieve_federation_trust_error_title": "Ophalen federatievertrouwen"
13
+ "oid4vci_machine_retrieve_federation_trust_error_title": "Ophalen federatievertrouwen",
14
+ "oid4vci_machine_first_party_error_title": "Eerste partijstroom",
15
+ "oid4vci_machine_send_authorization_challenge_request_error_title": "Versturen autorisatie-uitdaging aanvraag",
16
+ "oid4vci_machine_create_config_error_title": "SiopV2-configuratie aanmaken",
17
+ "oid4vci_machine_get_request_error_title": "SiopV2-verzoek ophalen"
14
18
  }
@@ -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
  })