@sphereon/ssi-sdk.oid4vci-holder 0.34.1-next.3 → 0.34.1-next.322
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +650 -579
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -17
- package/dist/index.d.ts +27 -17
- package/dist/index.js +628 -557
- package/dist/index.js.map +1 -1
- package/package.json +25 -24
- package/src/agent/OID4VCIHolder.ts +109 -54
- package/src/machines/firstPartyMachine.ts +1 -1
- package/src/machines/oid4vciMachine.ts +38 -6
- package/src/mappers/OIDC4VCIBrandingMapper.ts +1 -1
- package/src/services/OID4VCIHolderService.ts +47 -48
- package/src/types/FirstPartyMachine.ts +6 -5
- package/src/types/IOID4VCIHolder.ts +22 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sphereon/ssi-sdk.oid4vci-holder",
|
|
3
|
-
"version": "0.34.1-next.
|
|
3
|
+
"version": "0.34.1-next.322+78f8dd31",
|
|
4
4
|
"source": "src/index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -26,40 +26,41 @@
|
|
|
26
26
|
"build": "tsup --config ../../tsup.config.ts --tsconfig ../../tsconfig.tsup.json"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@sphereon/did-auth-siop": "0.19.
|
|
29
|
+
"@sphereon/did-auth-siop": "0.19.1-next.234",
|
|
30
30
|
"@sphereon/kmp-mdoc-core": "0.2.0-SNAPSHOT.26",
|
|
31
|
-
"@sphereon/oid4vci-client": "0.19.
|
|
32
|
-
"@sphereon/oid4vci-common": "0.19.
|
|
33
|
-
"@sphereon/ssi-sdk-ext.did-utils": "0.
|
|
34
|
-
"@sphereon/ssi-sdk-ext.identifier-resolution": "0.
|
|
35
|
-
"@sphereon/ssi-sdk-ext.jwt-service": "0.
|
|
36
|
-
"@sphereon/ssi-sdk-ext.key-utils": "0.
|
|
37
|
-
"@sphereon/ssi-sdk.contact-manager": "0.34.1-next.
|
|
38
|
-
"@sphereon/ssi-sdk.core": "0.34.1-next.
|
|
39
|
-
"@sphereon/ssi-sdk.credential-store": "0.34.1-next.
|
|
40
|
-
"@sphereon/ssi-sdk.credential-validation": "0.34.1-next.
|
|
41
|
-
"@sphereon/ssi-sdk.data-store": "0.34.1-next.
|
|
42
|
-
"@sphereon/ssi-sdk.issuance-branding": "0.34.1-next.
|
|
43
|
-
"@sphereon/ssi-sdk.mdl-mdoc": "0.34.1-next.
|
|
44
|
-
"@sphereon/ssi-sdk.oidf-client": "0.34.1-next.
|
|
45
|
-
"@sphereon/ssi-sdk.sd-jwt": "0.34.1-next.
|
|
46
|
-
"@sphereon/ssi-sdk.siopv2-oid4vp-common": "0.34.1-next.
|
|
47
|
-
"@sphereon/ssi-sdk.siopv2-oid4vp-op-auth": "0.34.1-next.
|
|
48
|
-
"@sphereon/ssi-sdk.xstate-machine-persistence": "0.34.1-next.
|
|
49
|
-
"@sphereon/ssi-types": "0.34.1-next.
|
|
31
|
+
"@sphereon/oid4vci-client": "0.19.1-next.234",
|
|
32
|
+
"@sphereon/oid4vci-common": "0.19.1-next.234",
|
|
33
|
+
"@sphereon/ssi-sdk-ext.did-utils": "0.34.1-next.322+78f8dd31",
|
|
34
|
+
"@sphereon/ssi-sdk-ext.identifier-resolution": "0.34.1-next.322+78f8dd31",
|
|
35
|
+
"@sphereon/ssi-sdk-ext.jwt-service": "0.34.1-next.322+78f8dd31",
|
|
36
|
+
"@sphereon/ssi-sdk-ext.key-utils": "0.34.1-next.322+78f8dd31",
|
|
37
|
+
"@sphereon/ssi-sdk.contact-manager": "0.34.1-next.322+78f8dd31",
|
|
38
|
+
"@sphereon/ssi-sdk.core": "0.34.1-next.322+78f8dd31",
|
|
39
|
+
"@sphereon/ssi-sdk.credential-store": "0.34.1-next.322+78f8dd31",
|
|
40
|
+
"@sphereon/ssi-sdk.credential-validation": "0.34.1-next.322+78f8dd31",
|
|
41
|
+
"@sphereon/ssi-sdk.data-store-types": "0.34.1-next.322+78f8dd31",
|
|
42
|
+
"@sphereon/ssi-sdk.issuance-branding": "0.34.1-next.322+78f8dd31",
|
|
43
|
+
"@sphereon/ssi-sdk.mdl-mdoc": "0.34.1-next.322+78f8dd31",
|
|
44
|
+
"@sphereon/ssi-sdk.oidf-client": "0.34.1-next.322+78f8dd31",
|
|
45
|
+
"@sphereon/ssi-sdk.sd-jwt": "0.34.1-next.322+78f8dd31",
|
|
46
|
+
"@sphereon/ssi-sdk.siopv2-oid4vp-common": "0.34.1-next.322+78f8dd31",
|
|
47
|
+
"@sphereon/ssi-sdk.siopv2-oid4vp-op-auth": "0.34.1-next.322+78f8dd31",
|
|
48
|
+
"@sphereon/ssi-sdk.xstate-machine-persistence": "0.34.1-next.322+78f8dd31",
|
|
49
|
+
"@sphereon/ssi-types": "0.34.1-next.322+78f8dd31",
|
|
50
50
|
"@veramo/core": "4.2.0",
|
|
51
51
|
"@veramo/data-store": "4.2.0",
|
|
52
52
|
"@veramo/utils": "4.2.0",
|
|
53
53
|
"ajv": "^8.17.1",
|
|
54
54
|
"ajv-formats": "^3.0.1",
|
|
55
|
+
"dcql": "1.0.1",
|
|
55
56
|
"i18n-js": "^3.9.2",
|
|
56
57
|
"lodash.memoize": "^4.1.2",
|
|
57
58
|
"uuid": "^9.0.1",
|
|
58
59
|
"xstate": "^4.38.3"
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
|
-
"@sphereon/oid4vc-common": "0.19.
|
|
62
|
-
"@sphereon/ssi-sdk-ext.did-resolver-jwk": "0.
|
|
62
|
+
"@sphereon/oid4vc-common": "0.19.1-next.234",
|
|
63
|
+
"@sphereon/ssi-sdk-ext.did-resolver-jwk": "0.34.1-next.322+78f8dd31",
|
|
63
64
|
"@sphereon/ssi-sdk.siopv2-oid4vp-common": "workspace:*",
|
|
64
65
|
"@types/i18n-js": "^3.8.9",
|
|
65
66
|
"@types/lodash.memoize": "^4.1.9",
|
|
@@ -89,5 +90,5 @@
|
|
|
89
90
|
"OID4VCI",
|
|
90
91
|
"State Machine"
|
|
91
92
|
],
|
|
92
|
-
"gitHead": "
|
|
93
|
+
"gitHead": "78f8dd3157066ae8cf11d2ae50c8c3d8f43b8ed0"
|
|
93
94
|
}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import { CredentialOfferClient, MetadataClient, OpenID4VCIClient } from '@sphereon/oid4vci-client'
|
|
1
|
+
import { CredentialOfferClient, MetadataClient, OpenID4VCIClient, OpenID4VCIClientV1_0_15 } from '@sphereon/oid4vci-client'
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
AuthorizationDetailsV1_0_15,
|
|
4
4
|
AuthorizationRequestOpts,
|
|
5
5
|
AuthorizationServerClientOpts,
|
|
6
6
|
AuthorizationServerOpts,
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
CredentialConfigurationSupportedJwtVcJsonLdAndLdpVcV1_0_15,
|
|
8
|
+
CredentialDefinitionJwtVcJsonLdAndLdpVcV1_0_15,
|
|
9
9
|
CredentialOfferRequestWithBaseUrl,
|
|
10
10
|
DefaultURISchemes,
|
|
11
11
|
EndpointMetadataResult,
|
|
12
|
-
getTypesFromAuthorizationDetails,
|
|
13
|
-
getTypesFromCredentialOffer,
|
|
14
12
|
getTypesFromObject,
|
|
15
13
|
Jwt,
|
|
16
14
|
NotificationRequest,
|
|
@@ -30,11 +28,11 @@ import {
|
|
|
30
28
|
} from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
31
29
|
import { IJwtService, JwsHeader } from '@sphereon/ssi-sdk-ext.jwt-service'
|
|
32
30
|
import { signatureAlgorithmFromKey } from '@sphereon/ssi-sdk-ext.key-utils'
|
|
31
|
+
import { defaultHasher } from '@sphereon/ssi-sdk.core'
|
|
33
32
|
import {
|
|
34
33
|
ConnectionType,
|
|
35
34
|
CorrelationIdentifierType,
|
|
36
35
|
CredentialCorrelationType,
|
|
37
|
-
CredentialRole,
|
|
38
36
|
ensureRawDocument,
|
|
39
37
|
FindPartyArgs,
|
|
40
38
|
IBasicCredentialLocaleBranding,
|
|
@@ -44,17 +42,17 @@ import {
|
|
|
44
42
|
IIssuerLocaleBranding,
|
|
45
43
|
NonPersistedIdentity,
|
|
46
44
|
Party,
|
|
47
|
-
} from '@sphereon/ssi-sdk.data-store'
|
|
45
|
+
} from '@sphereon/ssi-sdk.data-store-types'
|
|
48
46
|
import {
|
|
49
47
|
CredentialMapper,
|
|
50
48
|
type CredentialProofFormat,
|
|
49
|
+
CredentialRole,
|
|
51
50
|
HasherSync,
|
|
52
51
|
IVerifiableCredential,
|
|
53
52
|
JoseSignatureAlgorithm,
|
|
54
53
|
JoseSignatureAlgorithmString,
|
|
55
54
|
JwtDecodedVerifiableCredential,
|
|
56
55
|
Loggers,
|
|
57
|
-
OriginalVerifiableCredential,
|
|
58
56
|
parseDid,
|
|
59
57
|
SdJwtDecodedVerifiableCredentialPayload,
|
|
60
58
|
WrappedW3CVerifiableCredential,
|
|
@@ -70,9 +68,22 @@ import {
|
|
|
70
68
|
W3CVerifiableCredential,
|
|
71
69
|
} from '@veramo/core'
|
|
72
70
|
import { asArray, computeEntryHash } from '@veramo/utils'
|
|
71
|
+
import fetch from 'cross-fetch'
|
|
73
72
|
import { decodeJWT } from 'did-jwt'
|
|
74
73
|
import { v4 as uuidv4 } from 'uuid'
|
|
75
74
|
import { OID4VCIMachine } from '../machines/oid4vciMachine'
|
|
75
|
+
import {
|
|
76
|
+
extractCredentialFromResponse,
|
|
77
|
+
getBasicIssuerLocaleBranding,
|
|
78
|
+
getCredentialBranding,
|
|
79
|
+
getCredentialConfigsSupportedMerged,
|
|
80
|
+
getIdentifierOpts,
|
|
81
|
+
getIssuanceOpts,
|
|
82
|
+
mapCredentialToAccept,
|
|
83
|
+
selectCredentialLocaleBranding,
|
|
84
|
+
startFirstPartApplicationMachine,
|
|
85
|
+
verifyCredentialToAccept,
|
|
86
|
+
} from '../services/OID4VCIHolderService'
|
|
76
87
|
import {
|
|
77
88
|
AddContactIdentityArgs,
|
|
78
89
|
AssertValidCredentialsArgs,
|
|
@@ -98,6 +109,8 @@ import {
|
|
|
98
109
|
OnContactIdentityCreatedArgs,
|
|
99
110
|
OnCredentialStoredArgs,
|
|
100
111
|
OnIdentifierCreatedArgs,
|
|
112
|
+
PrepareAuthorizationRequestArgs,
|
|
113
|
+
PrepareAuthorizationResult,
|
|
101
114
|
PrepareStartArgs,
|
|
102
115
|
RequestType,
|
|
103
116
|
RequiredContext,
|
|
@@ -111,19 +124,6 @@ import {
|
|
|
111
124
|
VerifyEBSICredentialIssuerArgs,
|
|
112
125
|
VerifyEBSICredentialIssuerResult,
|
|
113
126
|
} from '../types/IOID4VCIHolder'
|
|
114
|
-
import {
|
|
115
|
-
getBasicIssuerLocaleBranding,
|
|
116
|
-
getCredentialBranding,
|
|
117
|
-
getCredentialConfigsSupportedMerged,
|
|
118
|
-
getIdentifierOpts,
|
|
119
|
-
getIssuanceOpts,
|
|
120
|
-
mapCredentialToAccept,
|
|
121
|
-
selectCredentialLocaleBranding,
|
|
122
|
-
startFirstPartApplicationMachine,
|
|
123
|
-
verifyCredentialToAccept,
|
|
124
|
-
} from '../services/OID4VCIHolderService'
|
|
125
|
-
import 'cross-fetch/polyfill'
|
|
126
|
-
import { defaultHasher } from '@sphereon/ssi-sdk.core'
|
|
127
127
|
|
|
128
128
|
/**
|
|
129
129
|
* {@inheritDoc IOID4VCIHolder}
|
|
@@ -151,7 +151,7 @@ export function signCallback(
|
|
|
151
151
|
context: IAgentContext<IKeyManager & IDIDManager & IResolver & IIdentifierResolution & IJwtService>,
|
|
152
152
|
nonce?: string,
|
|
153
153
|
) {
|
|
154
|
-
return async (jwt: Jwt, kid?: string) => {
|
|
154
|
+
return async (jwt: Jwt, kid?: string, noIssPayloadUpdate?: boolean) => {
|
|
155
155
|
let resolution = await context.agent.identifierManagedGet(identifier)
|
|
156
156
|
const jwk = jwt.header.jwk ?? (resolution.method === 'jwk' ? resolution.jwk : undefined)
|
|
157
157
|
if (!resolution.issuer && !jwt.payload.iss) {
|
|
@@ -170,7 +170,7 @@ export function signCallback(
|
|
|
170
170
|
}
|
|
171
171
|
return (
|
|
172
172
|
await context.agent.jwtCreateJwsCompactSignature({
|
|
173
|
-
issuer: { ...resolution, noIssPayloadUpdate: false },
|
|
173
|
+
issuer: { ...resolution, noIssPayloadUpdate: noIssPayloadUpdate ?? false },
|
|
174
174
|
protectedHeader: header,
|
|
175
175
|
payload,
|
|
176
176
|
})
|
|
@@ -216,6 +216,7 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
216
216
|
oid4vciHolderStart: this.oid4vciHolderStart.bind(this),
|
|
217
217
|
oid4vciHolderGetIssuerMetadata: this.oid4vciHolderGetIssuerMetadata.bind(this),
|
|
218
218
|
oid4vciHolderGetMachineInterpreter: this.oid4vciHolderGetMachineInterpreter.bind(this),
|
|
219
|
+
oid4vciHolderPrepareAuthorizationRequest: this.oid4vciHolderPrepareAuthorizationRequest.bind(this),
|
|
219
220
|
oid4vciHolderCreateCredentialsToSelectFrom: this.oid4vciHolderCreateCredentialsToSelectFrom.bind(this),
|
|
220
221
|
oid4vciHolderGetContact: this.oid4vciHolderGetContact.bind(this),
|
|
221
222
|
oid4vciHolderGetCredentials: this.oid4vciHolderGetCredentials.bind(this),
|
|
@@ -229,7 +230,7 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
229
230
|
oid4vciHolderStoreIssuerBranding: this.oid4vciHolderStoreIssuerBranding.bind(this),
|
|
230
231
|
}
|
|
231
232
|
|
|
232
|
-
private readonly vcFormatPreferences: Array<string> = ['vc+sd-jwt', 'mso_mdoc', 'jwt_vc_json', 'jwt_vc', 'ldp_vc']
|
|
233
|
+
private readonly vcFormatPreferences: Array<string> = ['dc+sd-jwt', 'vc+sd-jwt', 'mso_mdoc', 'jwt_vc_json', 'jwt_vc', 'ldp_vc'] // TODO see SSISDK-52 concerning vc+sd-jwt
|
|
233
234
|
private readonly jsonldCryptographicSuitePreferences: Array<string> = [
|
|
234
235
|
'Ed25519Signature2018',
|
|
235
236
|
'EcdsaSecp256k1Signature2019',
|
|
@@ -326,6 +327,8 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
326
327
|
startFirstPartApplicationMachine({ ...args, stateNavigationListener: opts.firstPartyStateNavigationListener }, context),
|
|
327
328
|
[OID4VCIMachineServices.createCredentialsToSelectFrom]: (args: CreateCredentialsToSelectFromArgs) =>
|
|
328
329
|
this.oid4vciHolderCreateCredentialsToSelectFrom(args, context),
|
|
330
|
+
[OID4VCIMachineServices.prepareAuthorizationRequest]: (args: PrepareAuthorizationRequestArgs) =>
|
|
331
|
+
this.oid4vciHolderPrepareAuthorizationRequest(args, context),
|
|
329
332
|
[OID4VCIMachineServices.getContact]: (args: GetContactArgs) => this.oid4vciHolderGetContact(args, context),
|
|
330
333
|
[OID4VCIMachineServices.getCredentials]: (args: GetCredentialsArgs) =>
|
|
331
334
|
this.oid4vciHolderGetCredentials({ accessTokenOpts: args.accessTokenOpts ?? opts.accessTokenOpts, ...args }, context),
|
|
@@ -375,11 +378,9 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
375
378
|
}
|
|
376
379
|
|
|
377
380
|
const authorizationRequestOpts = { ...this.defaultAuthorizationRequestOpts, ...args.authorizationRequestOpts } satisfies AuthorizationRequestOpts
|
|
378
|
-
//
|
|
381
|
+
// TODO: Previously we filtered the details first against our vcformat prefs. However auth details does not have the notion of formats anymore
|
|
379
382
|
authorizationRequestOpts.authorizationDetails = authorizationRequestOpts?.authorizationDetails
|
|
380
|
-
? asArray(authorizationRequestOpts.authorizationDetails)
|
|
381
|
-
(detail) => typeof detail === 'string' || this.vcFormatPreferences.includes(detail.format),
|
|
382
|
-
)
|
|
383
|
+
? asArray(authorizationRequestOpts.authorizationDetails)
|
|
383
384
|
: undefined
|
|
384
385
|
|
|
385
386
|
if (!authorizationRequestOpts.redirectUri) {
|
|
@@ -391,19 +392,19 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
391
392
|
authorizationRequestOpts.clientId = authorizationRequestOpts.redirectUri
|
|
392
393
|
}
|
|
393
394
|
|
|
395
|
+
// TODO: This entire filter and formats population should not work anymore, as the auth details no longer have the format property.
|
|
394
396
|
let formats: string[] = this.vcFormatPreferences
|
|
395
397
|
const authFormats = authorizationRequestOpts?.authorizationDetails
|
|
396
|
-
?.map((detail:
|
|
398
|
+
?.map((detail: AuthorizationDetailsV1_0_15) => (typeof detail === 'object' && 'format' in detail && detail.format ? detail.format : undefined))
|
|
397
399
|
.filter((format) => !!format)
|
|
398
400
|
.map((format) => format as string)
|
|
399
401
|
if (authFormats && authFormats.length > 0) {
|
|
400
402
|
formats = Array.from(new Set(authFormats))
|
|
401
403
|
}
|
|
402
|
-
let oid4vciClient:
|
|
403
|
-
let types: string[][] | undefined = undefined
|
|
404
|
+
let oid4vciClient: OpenID4VCIClientV1_0_15
|
|
404
405
|
let offer: CredentialOfferRequestWithBaseUrl | undefined
|
|
405
406
|
if (requestData.existingClientState) {
|
|
406
|
-
oid4vciClient = await
|
|
407
|
+
oid4vciClient = await OpenID4VCIClientV1_0_15.fromState({ state: requestData.existingClientState })
|
|
407
408
|
offer = oid4vciClient.credentialOffer
|
|
408
409
|
} else {
|
|
409
410
|
offer = requestData.credentialOffer
|
|
@@ -425,46 +426,44 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
425
426
|
if (!offer) {
|
|
426
427
|
// else no offer, meaning we have an issuer URL
|
|
427
428
|
logger.log(`Issuer url received (no credential offer): ${uri}`)
|
|
428
|
-
oid4vciClient = await
|
|
429
|
+
oid4vciClient = await OpenID4VCIClientV1_0_15.fromCredentialIssuer({
|
|
429
430
|
credentialIssuer: uri,
|
|
430
431
|
authorizationRequest: authorizationRequestOpts,
|
|
431
432
|
clientId: authorizationRequestOpts.clientId,
|
|
432
|
-
createAuthorizationRequestURL: requestData.createAuthorizationRequestURL ?? true,
|
|
433
|
+
createAuthorizationRequestURL: false, // requestData.createAuthorizationRequestURL ?? true,
|
|
433
434
|
})
|
|
434
435
|
} else {
|
|
435
436
|
logger.log(`Credential offer received: ${uri}`)
|
|
436
|
-
oid4vciClient = await
|
|
437
|
+
oid4vciClient = await OpenID4VCIClientV1_0_15.fromURI({
|
|
437
438
|
uri,
|
|
438
439
|
authorizationRequest: authorizationRequestOpts,
|
|
439
440
|
clientId: authorizationRequestOpts.clientId,
|
|
440
|
-
createAuthorizationRequestURL: requestData.createAuthorizationRequestURL ?? true,
|
|
441
|
+
createAuthorizationRequestURL: false, // requestData.createAuthorizationRequestURL ?? true,
|
|
441
442
|
})
|
|
442
443
|
}
|
|
443
444
|
}
|
|
444
445
|
|
|
446
|
+
let configurationIds: Array<string> = []
|
|
445
447
|
if (offer) {
|
|
446
|
-
|
|
448
|
+
configurationIds = offer.original_credential_offer.credential_configuration_ids
|
|
447
449
|
} else {
|
|
448
|
-
|
|
449
|
-
.
|
|
450
|
-
.
|
|
450
|
+
configurationIds = asArray(authorizationRequestOpts.authorizationDetails)
|
|
451
|
+
// .filter((authDetails): authDetails is Exclude<AuthorizationDetailsV1_0_15, string> => typeof authDetails !== 'string')
|
|
452
|
+
.map((authReqOpts) => authReqOpts.credential_configuration_id)
|
|
453
|
+
.filter((id): id is string => !!id)
|
|
451
454
|
}
|
|
452
455
|
|
|
453
|
-
const serverMetadata = await oid4vciClient.retrieveServerMetadata()
|
|
454
456
|
const credentialsSupported = await getCredentialConfigsSupportedMerged({
|
|
455
457
|
client: oid4vciClient,
|
|
456
458
|
vcFormatPreferences: formats,
|
|
457
|
-
|
|
459
|
+
configurationIds,
|
|
458
460
|
})
|
|
461
|
+
|
|
462
|
+
const serverMetadata = await oid4vciClient.retrieveServerMetadata()
|
|
459
463
|
const credentialBranding = await getCredentialBranding({ credentialsSupported, context })
|
|
460
|
-
const authorizationCodeURL = oid4vciClient.authorizationURL
|
|
461
|
-
if (authorizationCodeURL) {
|
|
462
|
-
logger.log(`authorization code URL ${authorizationCodeURL}`)
|
|
463
|
-
}
|
|
464
464
|
const oid4vciClientState = JSON.parse(await oid4vciClient.exportState())
|
|
465
465
|
|
|
466
466
|
return {
|
|
467
|
-
authorizationCodeURL,
|
|
468
467
|
credentialBranding,
|
|
469
468
|
credentialsSupported,
|
|
470
469
|
serverMetadata,
|
|
@@ -472,6 +471,42 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
472
471
|
}
|
|
473
472
|
}
|
|
474
473
|
|
|
474
|
+
private async oid4vciHolderPrepareAuthorizationRequest(
|
|
475
|
+
args: PrepareAuthorizationRequestArgs,
|
|
476
|
+
context: RequiredContext,
|
|
477
|
+
): Promise<PrepareAuthorizationResult> {
|
|
478
|
+
const { openID4VCIClientState, contact } = args
|
|
479
|
+
if (!openID4VCIClientState) {
|
|
480
|
+
return Promise.reject(Error('Missing openID4VCI client state in context'))
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const clientId = contact?.identities
|
|
484
|
+
.map((identity) => {
|
|
485
|
+
const connectionConfig = identity.connection?.config
|
|
486
|
+
if (connectionConfig && 'clientId' in connectionConfig) {
|
|
487
|
+
return connectionConfig.clientId
|
|
488
|
+
}
|
|
489
|
+
return undefined
|
|
490
|
+
})
|
|
491
|
+
.find((clientId) => clientId)
|
|
492
|
+
|
|
493
|
+
if (!clientId) {
|
|
494
|
+
return Promise.reject(Error(`Missing client id in contact's connectionConfig`))
|
|
495
|
+
}
|
|
496
|
+
const client = await OpenID4VCIClient.fromState({ state: openID4VCIClientState })
|
|
497
|
+
const authorizationCodeURL = await client.createAuthorizationRequestUrl({
|
|
498
|
+
authorizationRequest: {
|
|
499
|
+
clientId: clientId,
|
|
500
|
+
} satisfies AuthorizationRequestOpts,
|
|
501
|
+
})
|
|
502
|
+
if (authorizationCodeURL) {
|
|
503
|
+
logger.log(`authorization code URL ${authorizationCodeURL}`)
|
|
504
|
+
}
|
|
505
|
+
return {
|
|
506
|
+
authorizationCodeURL,
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
475
510
|
private async oid4vciHolderCreateCredentialsToSelectFrom(
|
|
476
511
|
args: CreateCredentialsToSelectFromArgs,
|
|
477
512
|
context: RequiredContext,
|
|
@@ -587,7 +622,7 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
587
622
|
return Promise.reject(Error('Missing openID4VCI client state in context'))
|
|
588
623
|
}
|
|
589
624
|
|
|
590
|
-
const client = await
|
|
625
|
+
const client = await OpenID4VCIClientV1_0_15.fromState({ state: openID4VCIClientState })
|
|
591
626
|
const credentialsSupported = await getCredentialConfigsSupportedMerged({
|
|
592
627
|
client,
|
|
593
628
|
vcFormatPreferences: this.vcFormatPreferences,
|
|
@@ -849,11 +884,30 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
849
884
|
|
|
850
885
|
let counter = 0
|
|
851
886
|
for (const credentialId of selectedCredentials) {
|
|
852
|
-
|
|
887
|
+
// The selectedCredential from context is the configurationId, whilst we store the branding by type. We need to map
|
|
888
|
+
const configId = credentialId
|
|
889
|
+
const types =
|
|
890
|
+
credentialsToAccept
|
|
891
|
+
.find((ac) => ac.correlationId === configId || ac.credentialToAccept.id === configId || ac.types.includes(configId))
|
|
892
|
+
?.types?.filter((type) => type != 'VerifiableCredential') ?? []
|
|
893
|
+
|
|
894
|
+
const localeBranding: Array<IBasicCredentialLocaleBranding> = credentialBranding?.[configId] ?? []
|
|
895
|
+
if (localeBranding.length === 0) {
|
|
896
|
+
for (const type of types) {
|
|
897
|
+
const branding = credentialBranding?.[type] ?? []
|
|
898
|
+
if (branding.length > 0) {
|
|
899
|
+
localeBranding.push(...branding)
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
853
904
|
if (localeBranding && localeBranding.length > 0) {
|
|
854
905
|
const credential = credentialsToAccept.find(
|
|
855
906
|
(credAccept) =>
|
|
856
|
-
credAccept.credentialToAccept.id === credentialId ||
|
|
907
|
+
credAccept.credentialToAccept.id === credentialId ||
|
|
908
|
+
JSON.stringify(credAccept.types) === credentialId ||
|
|
909
|
+
JSON.stringify(credAccept.types.filter((cred) => cred !== 'VerifiableCredential')) === JSON.stringify(types) ||
|
|
910
|
+
credentialsToAccept[counter],
|
|
857
911
|
)!
|
|
858
912
|
counter++
|
|
859
913
|
await context.agent.ibAddCredentialBranding({
|
|
@@ -920,7 +974,8 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
920
974
|
? 'credential_accepted_holder_signed'
|
|
921
975
|
: 'credential_deleted_holder_signed'
|
|
922
976
|
logger.log(`Subject issuance/signing will be used, with event`, event)
|
|
923
|
-
|
|
977
|
+
|
|
978
|
+
const issuerVC = extractCredentialFromResponse(mappedCredentialToAccept.credentialToAccept.credentialResponse)
|
|
924
979
|
const wrappedIssuerVC = CredentialMapper.toWrappedVerifiableCredential(issuerVC, { hasher: this.hasher ?? defaultHasher })
|
|
925
980
|
console.log(`Wrapped VC: ${wrappedIssuerVC.type}, ${wrappedIssuerVC.format}`)
|
|
926
981
|
// We will use the subject of the VCI Issuer (the holder, as the issuer of the new credential, so the below is not a mistake!)
|
|
@@ -1150,9 +1205,9 @@ export class OID4VCIHolder implements IAgentPlugin {
|
|
|
1150
1205
|
return undefined
|
|
1151
1206
|
}
|
|
1152
1207
|
|
|
1153
|
-
private getCredentialDefinition(issuanceOpt: IssuanceOpts):
|
|
1208
|
+
private getCredentialDefinition(issuanceOpt: IssuanceOpts): CredentialDefinitionJwtVcJsonLdAndLdpVcV1_0_15 | undefined {
|
|
1154
1209
|
if (issuanceOpt.format == 'ldp_vc' || issuanceOpt.format == 'jwt_vc_json-ld') {
|
|
1155
|
-
return (issuanceOpt as
|
|
1210
|
+
return (issuanceOpt as CredentialConfigurationSupportedJwtVcJsonLdAndLdpVcV1_0_15).credential_definition
|
|
1156
1211
|
}
|
|
1157
1212
|
return undefined
|
|
1158
1213
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { assign, createMachine, DoneInvokeEvent, interpret } from 'xstate'
|
|
2
2
|
import { AuthorizationChallengeCodeResponse, AuthorizationChallengeError, AuthorizationChallengeErrorResponse } from '@sphereon/oid4vci-common'
|
|
3
|
-
import { DidAuthConfig } from '@sphereon/ssi-sdk.data-store'
|
|
3
|
+
import { DidAuthConfig } from '@sphereon/ssi-sdk.data-store-types'
|
|
4
4
|
import { CreateConfigResult } from '@sphereon/ssi-sdk.siopv2-oid4vp-op-auth'
|
|
5
5
|
import { createConfig, getSiopRequest, sendAuthorizationChallengeRequest, sendAuthorizationResponse } from '../services/FirstPartyMachineServices'
|
|
6
6
|
import { translate } from '../localization/Localization'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AuthorizationChallengeCodeResponse, AuthzFlowType, toAuthorizationResponsePayload } from '@sphereon/oid4vci-common'
|
|
2
|
-
import { IBasicIssuerLocaleBranding, Identity, IIssuerLocaleBranding, Party } from '@sphereon/ssi-sdk.data-store'
|
|
2
|
+
import { IBasicIssuerLocaleBranding, Identity, IIssuerLocaleBranding, Party } from '@sphereon/ssi-sdk.data-store-types'
|
|
3
3
|
import { assign, createMachine, DoneInvokeEvent, interpret } from 'xstate'
|
|
4
4
|
import { translate } from '../localization/Localization'
|
|
5
5
|
import {
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
SelectCredentialsEvent,
|
|
29
29
|
SetAuthorizationCodeURLEvent,
|
|
30
30
|
VerificationCodeEvent,
|
|
31
|
+
PrepareAuthorizationResult,
|
|
31
32
|
} from '../types/IOID4VCIHolder'
|
|
32
33
|
import { FirstPartyMachineStateTypes } from '../types/FirstPartyMachine'
|
|
33
34
|
|
|
@@ -98,9 +99,7 @@ const oid4vciRequireAuthorizationGuard = (ctx: OID4VCIMachineContext, _event: OI
|
|
|
98
99
|
throw Error('Missing openID4VCI client state in context')
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
if (
|
|
102
|
-
return false
|
|
103
|
-
} else if (openID4VCIClientState.authorizationRequestOpts) {
|
|
102
|
+
if (openID4VCIClientState.authorizationURL && openID4VCIClientState.authorizationRequestOpts) {
|
|
104
103
|
// We have authz options or there is not credential offer to begin with.
|
|
105
104
|
// We require authz as long as we do not have the authz code response
|
|
106
105
|
return !ctx.openID4VCIClientState?.authorizationCodeResponse
|
|
@@ -164,6 +163,9 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
164
163
|
[OID4VCIMachineServices.start]: {
|
|
165
164
|
data: StartResult
|
|
166
165
|
}
|
|
166
|
+
[OID4VCIMachineServices.prepareAuthorizationRequest]: {
|
|
167
|
+
data: PrepareAuthorizationResult
|
|
168
|
+
}
|
|
167
169
|
[OID4VCIMachineServices.createCredentialsToSelectFrom]: {
|
|
168
170
|
data: Array<CredentialToSelectFromResult>
|
|
169
171
|
}
|
|
@@ -208,7 +210,6 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
208
210
|
onDone: {
|
|
209
211
|
target: OID4VCIMachineStates.createCredentialsToSelectFrom,
|
|
210
212
|
actions: assign({
|
|
211
|
-
authorizationCodeURL: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<StartResult>) => _event.data.authorizationCodeURL,
|
|
212
213
|
credentialBranding: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<StartResult>) => _event.data.credentialBranding ?? {},
|
|
213
214
|
credentialsSupported: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<StartResult>) => _event.data.credentialsSupported,
|
|
214
215
|
serverMetadata: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<StartResult>) => _event.data.serverMetadata,
|
|
@@ -439,6 +440,10 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
439
440
|
target: OID4VCIMachineStates.startFirstPartApplicationFlow,
|
|
440
441
|
cond: OID4VCIMachineGuards.isFirstPartyApplication,
|
|
441
442
|
},
|
|
443
|
+
{
|
|
444
|
+
target: OID4VCIMachineStates.prepareAuthorizationRequest,
|
|
445
|
+
cond: OID4VCIMachineGuards.requireAuthorizationGuard,
|
|
446
|
+
},
|
|
442
447
|
{
|
|
443
448
|
target: OID4VCIMachineStates.initiateAuthorizationRequest,
|
|
444
449
|
cond: OID4VCIMachineGuards.requireAuthorizationGuard,
|
|
@@ -511,12 +516,16 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
511
516
|
target: OID4VCIMachineStates.startFirstPartApplicationFlow,
|
|
512
517
|
cond: OID4VCIMachineGuards.isFirstPartyApplication,
|
|
513
518
|
},
|
|
519
|
+
{
|
|
520
|
+
target: OID4VCIMachineStates.prepareAuthorizationRequest,
|
|
521
|
+
cond: OID4VCIMachineGuards.requireAuthorizationGuard,
|
|
522
|
+
},
|
|
514
523
|
{
|
|
515
524
|
target: OID4VCIMachineStates.verifyPin,
|
|
516
525
|
cond: OID4VCIMachineGuards.requirePinGuard,
|
|
517
526
|
},
|
|
518
527
|
{
|
|
519
|
-
target: OID4VCIMachineStates.
|
|
528
|
+
target: OID4VCIMachineStates.prepareAuthorizationRequest,
|
|
520
529
|
cond: OID4VCIMachineGuards.requireAuthorizationGuard,
|
|
521
530
|
},
|
|
522
531
|
{
|
|
@@ -524,6 +533,29 @@ const createOID4VCIMachine = (opts?: CreateOID4VCIMachineOpts): OID4VCIStateMach
|
|
|
524
533
|
},
|
|
525
534
|
],
|
|
526
535
|
},
|
|
536
|
+
[OID4VCIMachineStates.prepareAuthorizationRequest]: {
|
|
537
|
+
id: OID4VCIMachineStates.prepareAuthorizationRequest,
|
|
538
|
+
invoke: {
|
|
539
|
+
src: OID4VCIMachineServices.prepareAuthorizationRequest,
|
|
540
|
+
onDone: {
|
|
541
|
+
target: OID4VCIMachineStates.initiateAuthorizationRequest,
|
|
542
|
+
actions: assign({
|
|
543
|
+
authorizationCodeURL: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<PrepareAuthorizationResult>) =>
|
|
544
|
+
_event.data.authorizationCodeURL,
|
|
545
|
+
}),
|
|
546
|
+
},
|
|
547
|
+
onError: {
|
|
548
|
+
target: OID4VCIMachineStates.handleError,
|
|
549
|
+
actions: assign({
|
|
550
|
+
error: (_ctx: OID4VCIMachineContext, _event: DoneInvokeEvent<Error>): ErrorDetails => ({
|
|
551
|
+
title: translate('oid4vci_machine_prepare_authorization_error_title'),
|
|
552
|
+
message: _event.data.message,
|
|
553
|
+
stack: _event.data.stack,
|
|
554
|
+
}),
|
|
555
|
+
}),
|
|
556
|
+
},
|
|
557
|
+
},
|
|
558
|
+
},
|
|
527
559
|
[OID4VCIMachineStates.initiateAuthorizationRequest]: {
|
|
528
560
|
id: OID4VCIMachineStates.initiateAuthorizationRequest,
|
|
529
561
|
on: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CredentialsSupportedDisplay, NameAndLocale } from '@sphereon/oid4vci-common'
|
|
2
|
-
import { IBasicCredentialClaim, IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding } from '@sphereon/ssi-sdk.data-store'
|
|
2
|
+
import { IBasicCredentialClaim, IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding } from '@sphereon/ssi-sdk.data-store-types'
|
|
3
3
|
import { SdJwtClaimDisplayMetadata, SdJwtClaimMetadata, SdJwtClaimPath, SdJwtTypeDisplayMetadata } from '@sphereon/ssi-types'
|
|
4
4
|
import {
|
|
5
5
|
IssuerLocaleBrandingFromArgs,
|