@sphereon/ssi-sdk.siopv2-oid4vp-rp-auth 0.34.1-feature.SSISDK.57.uni.client.206 → 0.34.1-feature.SSISDK.58.host.nonce.endpoint.194

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.
@@ -5,12 +5,10 @@ import {
5
5
  AuthorizationResponseStateStatus,
6
6
  AuthorizationResponseStateWithVerifiedData,
7
7
  decodeUriAsJson,
8
- VerifiedAuthorizationResponse,
8
+ VerifiedAuthorizationResponse
9
9
  } from '@sphereon/did-auth-siop'
10
10
  import { getAgentResolver } from '@sphereon/ssi-sdk-ext.did-utils'
11
11
  import { shaHasher as defaultHasher } from '@sphereon/ssi-sdk.core'
12
- import { validate as isValidUUID } from 'uuid'
13
-
14
12
  import type { ImportDcqlQueryItem } from '@sphereon/ssi-sdk.pd-manager'
15
13
  import {
16
14
  AdditionalClaims,
@@ -88,11 +86,7 @@ export class SIOPv2RP implements IAgentPlugin {
88
86
 
89
87
  private async createAuthorizationRequestURI(createArgs: ICreateAuthRequestArgs, context: IRequiredContext): Promise<string> {
90
88
  return await this.getRPInstance(
91
- {
92
- createWhenNotPresent: true,
93
- responseRedirectURI: createArgs.responseRedirectURI,
94
- ...(createArgs.useQueryIdInstance === true && { queryId: createArgs.queryId }),
95
- },
89
+ { responseRedirectURI: createArgs.responseRedirectURI, ...(createArgs.useQueryIdInstance === true && { queryId: createArgs.queryId } ) },
96
90
  context,
97
91
  )
98
92
  .then((rp) => rp.createAuthorizationRequestURI(createArgs, context))
@@ -103,7 +97,7 @@ export class SIOPv2RP implements IAgentPlugin {
103
97
  createArgs: ICreateAuthRequestArgs,
104
98
  context: IRequiredContext,
105
99
  ): Promise<IAuthorizationRequestPayloads> {
106
- return await this.getRPInstance({ createWhenNotPresent: true, queryId: createArgs.queryId }, context)
100
+ return await this.getRPInstance({ queryId: createArgs.queryId }, context)
107
101
  .then((rp) => rp.createAuthorizationRequest(createArgs, context))
108
102
  .then(async (request) => {
109
103
  const authRequest: IAuthorizationRequestPayloads = {
@@ -116,8 +110,10 @@ export class SIOPv2RP implements IAgentPlugin {
116
110
  }
117
111
 
118
112
  private async siopGetRequestState(args: IGetAuthRequestStateArgs, context: IRequiredContext): Promise<AuthorizationRequestState | undefined> {
119
- return await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context).then((rp) =>
120
- rp.get(context).then((rp) => rp.sessionManager.getRequestStateByCorrelationId(args.correlationId, args.errorOnNotFound)),
113
+ return await this.getRPInstance({ queryId: args.queryId }, context).then((rp) =>
114
+ rp.get(context).then((rp) =>
115
+ rp.sessionManager.getRequestStateByCorrelationId(args.correlationId, args.errorOnNotFound)
116
+ ),
121
117
  )
122
118
  }
123
119
 
@@ -125,7 +121,7 @@ export class SIOPv2RP implements IAgentPlugin {
125
121
  args: IGetAuthResponseStateArgs,
126
122
  context: IRequiredContext,
127
123
  ): Promise<AuthorizationResponseStateWithVerifiedData | undefined> {
128
- const rpInstance: RPInstance = await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context)
124
+ const rpInstance: RPInstance = await this.getRPInstance({ queryId: args.queryId }, context)
129
125
  const authorizationResponseState: AuthorizationResponseState | undefined = await rpInstance
130
126
  .get(context)
131
127
  .then((rp) => rp.sessionManager.getResponseStateByCorrelationId(args.correlationId, args.errorOnNotFound))
@@ -205,7 +201,7 @@ export class SIOPv2RP implements IAgentPlugin {
205
201
  if (args.state !== 'authorization_request_created') {
206
202
  throw Error(`Only 'authorization_request_created' status is supported for this method at this point`)
207
203
  }
208
- return await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context)
204
+ return await this.getRPInstance({ queryId: args.queryId }, context)
209
205
  // todo: In the SIOP library we need to update the signal method to be more like this method
210
206
  .then((rp) =>
211
207
  rp.get(context).then(async (rp) => {
@@ -219,7 +215,7 @@ export class SIOPv2RP implements IAgentPlugin {
219
215
  }
220
216
 
221
217
  private async siopDeleteState(args: IGetAuthResponseStateArgs, context: IRequiredContext): Promise<boolean> {
222
- return await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context)
218
+ return await this.getRPInstance({ queryId: args.queryId }, context)
223
219
  .then((rp) => rp.get(context).then((rp) => rp.sessionManager.deleteStateForCorrelationId(args.correlationId)))
224
220
  .then(() => true)
225
221
  }
@@ -232,12 +228,12 @@ export class SIOPv2RP implements IAgentPlugin {
232
228
  typeof args.authorizationResponse === 'string'
233
229
  ? (decodeUriAsJson(args.authorizationResponse) as AuthorizationResponsePayload)
234
230
  : args.authorizationResponse
235
- return await this.getRPInstance({ createWhenNotPresent: false, queryId: args.queryId }, context).then((rp) =>
231
+ return await this.getRPInstance({ queryId: args.queryId }, context).then((rp) =>
236
232
  rp.get(context).then((rp) =>
237
233
  rp.verifyAuthorizationResponse(authResponse, {
238
234
  correlationId: args.correlationId,
239
- ...(args.dcqlQuery ? { dcqlQuery: args.dcqlQuery } : {}),
240
- audience: args.audience,
235
+ ...(args.dcqlQuery ? { dcqlQuery: args.dcqlQuery } : {}),
236
+ audience: args.audience,
241
237
  }),
242
238
  ),
243
239
  )
@@ -279,36 +275,9 @@ export class SIOPv2RP implements IAgentPlugin {
279
275
  return undefined
280
276
  }
281
277
 
282
- async getRPInstance({ createWhenNotPresent, queryId, responseRedirectURI }: ISiopRPInstanceArgs, context: IRequiredContext): Promise<RPInstance> {
283
- let rpInstanceId: string = SIOPv2RP._DEFAULT_OPTS_KEY
284
- let rpInstance: RPInstance | undefined
285
- if (queryId) {
286
- if (this.instances.has(queryId)) {
287
- rpInstanceId = queryId
288
- rpInstance = this.instances.get(rpInstanceId)!
289
- } else if (isValidUUID(queryId)) {
290
- try {
291
- // Check whether queryId is actually the PD item id
292
- const pd = await context.agent.pdmGetDefinition({ itemId: queryId })
293
- if (this.instances.has(pd.queryId)) {
294
- rpInstanceId = pd.queryId
295
- rpInstance = this.instances.get(rpInstanceId)!
296
- }
297
- } catch (ignore) {}
298
- }
299
- if (createWhenNotPresent) {
300
- rpInstanceId = queryId
301
- } else {
302
- rpInstance = this.instances.get(rpInstanceId)
303
- }
304
- } else {
305
- rpInstance = this.instances.get(rpInstanceId)
306
- }
307
-
308
- if (!rpInstance) {
309
- if (!createWhenNotPresent) {
310
- return Promise.reject(`No RP instance found for key ${rpInstanceId}`)
311
- }
278
+ async getRPInstance({ queryId, responseRedirectURI }: ISiopRPInstanceArgs, context: IRequiredContext): Promise<RPInstance> {
279
+ const instanceId = queryId ?? SIOPv2RP._DEFAULT_OPTS_KEY
280
+ if (!this.instances.has(instanceId)) {
312
281
  const instanceOpts = this.getInstanceOpts(queryId)
313
282
  const rpOpts = await this.getRPOptions(context, { queryId, responseRedirectURI: responseRedirectURI })
314
283
  if (!rpOpts.identifierOpts.resolveOpts?.resolver || typeof rpOpts.identifierOpts.resolveOpts.resolver.resolve !== 'function') {
@@ -323,9 +292,9 @@ export class SIOPv2RP implements IAgentPlugin {
323
292
  resolverResolution: true,
324
293
  })
325
294
  }
326
- rpInstance = new RPInstance({ rpOpts, pexOpts: instanceOpts })
327
- this.instances.set(rpInstanceId, rpInstance)
295
+ this.instances.set(instanceId, new RPInstance({ rpOpts, pexOpts: instanceOpts }))
328
296
  }
297
+ const rpInstance = this.instances.get(instanceId)!
329
298
  if (responseRedirectURI) {
330
299
  rpInstance.rpOptions.responseRedirectUri = responseRedirectURI
331
300
  }
@@ -367,22 +336,22 @@ export class SIOPv2RP implements IAgentPlugin {
367
336
  return options
368
337
  }
369
338
 
370
- getInstanceOpts(queryId?: string): IPEXInstanceOptions | undefined {
339
+ getInstanceOpts(definitionId?: string): IPEXInstanceOptions | undefined {
371
340
  if (!this.opts.instanceOpts) return undefined
372
341
 
373
- const instanceOpt = queryId ? this.opts.instanceOpts.find((i) => i.queryId === queryId) : undefined
342
+ const instanceOpt = definitionId ? this.opts.instanceOpts.find((i) => i.queryId === definitionId) : undefined
374
343
 
375
- return instanceOpt ?? this.getDefaultOptions(queryId)
344
+ return instanceOpt ?? this.getDefaultOptions(definitionId)
376
345
  }
377
346
 
378
- private getDefaultOptions(queryId: string | undefined) {
347
+ private getDefaultOptions(definitionId: string | undefined) {
379
348
  if (!this.opts.instanceOpts) return undefined
380
349
 
381
350
  const defaultOptions = this.opts.instanceOpts.find((i) => i.queryId === 'default')
382
351
  if (defaultOptions) {
383
352
  const clonedOptions = { ...defaultOptions }
384
- if (queryId !== undefined) {
385
- clonedOptions.queryId = queryId
353
+ if (definitionId !== undefined) {
354
+ clonedOptions.queryId = definitionId
386
355
  }
387
356
  return clonedOptions
388
357
  }
package/src/functions.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  ClientIdentifierPrefix,
3
3
  ClientMetadataOpts,
4
- DcqlQueryLookupCallback,
5
4
  InMemoryRPSessionManager,
6
5
  PassBy,
7
6
  PresentationVerificationCallback,
@@ -15,7 +14,7 @@ import {
15
14
  Scope,
16
15
  SubjectType,
17
16
  SupportedVersion,
18
- VerifyJwtCallback,
17
+ VerifyJwtCallback
19
18
  } from '@sphereon/did-auth-siop'
20
19
  import { CreateJwtCallback, JwtHeader, JwtIssuer, JwtPayload, SigningAlgo } from '@sphereon/oid4vc-common'
21
20
  import { IPresentationDefinition } from '@sphereon/pex'
@@ -35,7 +34,7 @@ import { TKeyType } from '@veramo/core'
35
34
  import { JWTVerifyOptions } from 'did-jwt'
36
35
  import { Resolvable } from 'did-resolver'
37
36
  import { EventEmitter } from 'events'
38
- import { IRequiredContext, IRPOptions, ISIOPIdentifierOptions } from './types/ISIOPv2RP'
37
+ import { IPEXOptions, IRequiredContext, IRPOptions, ISIOPIdentifierOptions } from './types/ISIOPv2RP'
39
38
  import { DcqlQuery } from 'dcql'
40
39
  import { defaultHasher } from '@sphereon/ssi-sdk.core'
41
40
 
@@ -43,7 +42,7 @@ export function getRequestVersion(rpOptions: IRPOptions): SupportedVersion {
43
42
  if (Array.isArray(rpOptions.supportedVersions) && rpOptions.supportedVersions.length > 0) {
44
43
  return rpOptions.supportedVersions[0]
45
44
  }
46
- return SupportedVersion.OID4VP_v1
45
+ return SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1
47
46
  }
48
47
 
49
48
  function getWellKnownDIDVerifyCallback(siopIdentifierOpts: ISIOPIdentifierOptions, context: IRequiredContext) {
@@ -58,31 +57,6 @@ function getWellKnownDIDVerifyCallback(siopIdentifierOpts: ISIOPIdentifierOption
58
57
  }
59
58
  }
60
59
 
61
- export function getDcqlQueryLookupCallback(context: IRequiredContext): DcqlQueryLookupCallback {
62
- async function dcqlQueryLookup(queryId: string, version?: string, tenantId?: string): Promise<DcqlQuery> {
63
- // TODO Add caching?
64
- const result = await context.agent.pdmGetDefinitions({
65
- filter: [
66
- {
67
- queryId,
68
- ...(tenantId && { tenantId }),
69
- ...(version && { version }),
70
- },
71
- {
72
- id: queryId,
73
- },
74
- ],
75
- })
76
- if (result && result.length > 0) {
77
- return result[0].query
78
- }
79
-
80
- return Promise.reject(Error(`No dcql query found for queryId ${queryId}`))
81
- }
82
-
83
- return dcqlQueryLookup
84
- }
85
-
86
60
  export function getPresentationVerificationCallback(
87
61
  idOpts: ManagedIdentifierOptsOrResult,
88
62
  context: IRequiredContext,
@@ -127,11 +101,34 @@ export function getPresentationVerificationCallback(
127
101
 
128
102
  export async function createRPBuilder(args: {
129
103
  rpOpts: IRPOptions
104
+ pexOpts?: IPEXOptions | undefined
130
105
  definition?: IPresentationDefinition
106
+ dcql?: DcqlQuery
131
107
  context: IRequiredContext
132
108
  }): Promise<RPBuilder> {
133
- const { rpOpts, context } = args
109
+ const { rpOpts, pexOpts, context } = args
134
110
  const { identifierOpts } = rpOpts
111
+ let definition: IPresentationDefinition | undefined = args.definition
112
+ let dcqlQuery: DcqlQuery | undefined = args.dcql
113
+
114
+ if (!definition && pexOpts && pexOpts.queryId) {
115
+ const presentationDefinitionItems = await context.agent.pdmGetDefinitions({
116
+ filter: [
117
+ {
118
+ queryId: pexOpts.queryId,
119
+ version: pexOpts.version,
120
+ tenantId: pexOpts.tenantId,
121
+ },
122
+ ],
123
+ })
124
+
125
+ if (presentationDefinitionItems.length > 0) {
126
+ const presentationDefinitionItem = presentationDefinitionItems[0]
127
+ if (!dcqlQuery && presentationDefinitionItem.dcqlPayload) {
128
+ dcqlQuery = presentationDefinitionItem.dcqlPayload.dcqlQuery as DcqlQuery // cast from DcqlQueryREST back to valibot DcqlQuery
129
+ }
130
+ }
131
+ }
135
132
 
136
133
  const didMethods = identifierOpts.supportedDIDMethods ?? (await getAgentDIDMethods(context))
137
134
  const eventEmitter = rpOpts.eventEmitter ?? new EventEmitter()
@@ -171,7 +168,9 @@ export async function createRPBuilder(args: {
171
168
  .withResponseMode(rpOpts.responseMode ?? ResponseMode.POST)
172
169
  .withResponseType(ResponseType.VP_TOKEN, PropertyTarget.REQUEST_OBJECT)
173
170
  // todo: move to options fill/correct method
174
- .withSupportedVersions(rpOpts.supportedVersions ?? [SupportedVersion.OID4VP_v1, SupportedVersion.SIOPv2_OID4VP_D28])
171
+ .withSupportedVersions(
172
+ rpOpts.supportedVersions ?? [SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1, SupportedVersion.SIOPv2_ID1, SupportedVersion.SIOPv2_D11],
173
+ )
175
174
 
176
175
  .withEventEmitter(eventEmitter)
177
176
  .withSessionManager(rpOpts.sessionManager ?? new InMemoryRPSessionManager(eventEmitter))
@@ -190,7 +189,6 @@ export async function createRPBuilder(args: {
190
189
  context,
191
190
  ),
192
191
  )
193
- .withDcqlQueryLookup(getDcqlQueryLookupCallback(context))
194
192
  .withRevocationVerification(RevocationVerification.NEVER)
195
193
  .withPresentationVerification(getPresentationVerificationCallback(identifierOpts.idOpts, context))
196
194
 
@@ -199,12 +197,11 @@ export async function createRPBuilder(args: {
199
197
  builder.withEntityId(oidfOpts.identifier, PropertyTarget.REQUEST_OBJECT)
200
198
  } else {
201
199
  const resolution = await context.agent.identifierManagedGet(identifierOpts.idOpts)
202
- const clientId: string =
203
- rpOpts.clientMetadataOpts?.client_id ??
204
- resolution.issuer ??
205
- (isManagedIdentifierDidResult(resolution) ? resolution.did : resolution.jwkThumbprint)
206
- const clientIdPrefixed = prefixClientId(clientId)
207
- builder.withClientId(clientIdPrefixed, PropertyTarget.REQUEST_OBJECT)
200
+ const clientId: string = rpOpts.clientMetadataOpts?.client_id ??
201
+ resolution.issuer ?? (isManagedIdentifierDidResult(resolution) ? resolution.did : resolution.jwkThumbprint)
202
+ const clientIdPrefixed = prefixClientId(clientId)
203
+ builder.withClientId(clientIdPrefixed, PropertyTarget.REQUEST_OBJECT
204
+ )
208
205
  }
209
206
 
210
207
  if (hasher) {
@@ -218,6 +215,10 @@ export async function createRPBuilder(args: {
218
215
  //fixme: this has been removed in the new version of did-auth-siop
219
216
  // builder.withWellknownDIDVerifyCallback(getWellKnownDIDVerifyCallback(didOpts, context))
220
217
 
218
+ if (dcqlQuery) {
219
+ builder.withDcqlQuery(dcqlQuery)
220
+ }
221
+
221
222
  if (rpOpts.responseRedirectUri) {
222
223
  builder.withResponseRedirectUri(rpOpts.responseRedirectUri)
223
224
  }
@@ -302,8 +303,8 @@ export function getSigningAlgo(type: TKeyType): SigningAlgo {
302
303
  export function prefixClientId(clientId: string): string {
303
304
  // FIXME SSISDK-60
304
305
  if (clientId.startsWith('did:')) {
305
- return `${ClientIdentifierPrefix.DECENTRALIZED_IDENTIFIER}:${clientId}`
306
+ return `${ClientIdentifierPrefix.DECENTRALIZED_IDENTIFIER}:${clientId}`;
306
307
  }
307
308
 
308
- return clientId
309
+ return clientId;
309
310
  }
@@ -32,7 +32,6 @@ import { HasherSync } from '@sphereon/ssi-types'
32
32
  import { VerifyCallback } from '@sphereon/wellknown-dids-client'
33
33
  import { IAgentContext, ICredentialVerifier, IDIDManager, IKeyManager, IPluginMethodMap, IResolver } from '@veramo/core'
34
34
  import { DcqlQuery } from 'dcql'
35
-
36
35
  import { Resolvable } from 'did-resolver'
37
36
  import { EventEmitter } from 'events'
38
37
 
@@ -137,12 +136,11 @@ export interface IPEXDefinitionPersistArgs extends IPEXInstanceOptions {
137
136
  }
138
137
 
139
138
  export interface ISiopRPInstanceArgs {
140
- createWhenNotPresent: boolean
141
139
  queryId?: string
142
140
  responseRedirectURI?: string
143
141
  }
144
142
 
145
- export interface IPEXInstanceOptions extends IPresentationOptions {
143
+ export interface IPEXInstanceOptions extends IPEXOptions {
146
144
  rpOpts?: IRPOptions
147
145
  }
148
146
 
@@ -160,9 +158,12 @@ export interface IRPOptions {
160
158
  responseRedirectUri?: string
161
159
  }
162
160
 
163
- export interface IPresentationOptions {
164
- queryId: string
161
+ export interface IPEXOptions {
165
162
  presentationVerifyCallback?: PresentationVerificationCallback
163
+ // definition?: IPresentationDefinition
164
+ queryId: string
165
+ version?: string
166
+ tenantId?: string
166
167
  }
167
168
 
168
169
  export type VerificationPolicies = {