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