Skip to content

Commit 2f334a1

Browse files
authored
Merge pull request #206 from Sphereon-Opensource/feature/SSISDK-65_redirect-fix
feature/SSISDK-65_redirect-fix
2 parents 8d5cffe + 3df4a72 commit 2f334a1

11 files changed

Lines changed: 64 additions & 25 deletions

File tree

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
"fix:lint": "biome lint --error-on-warnings",
1414
"fix:prettier": "biome format --write",
1515
"build": "turbo run build",
16-
"test:ci": "vitest run --config ./vitest.config.ts --coverage",
16+
"test:ci": "vitest run --config vitest.config.mts --coverage",
1717
"test": "turbo run test:vitest",
18-
"test:vitest": "vitest run --config ./vitest.config.ts --coverage",
18+
"test:vitest": "vitest run --config vitest.config.mts --coverage",
1919
"clean": "rimraf --glob **/dist **/.turbo **/.tsup **/coverage **/pnpm-lock.yaml packages/**/node_modules node_modules packages/**/tsconfig.tsbuildinfo",
2020
"publish:latest": "lerna publish --conventional-commits --include-merged-tags --create-release github --yes --dist-tag latest --registry https://registry.npmjs.org",
2121
"publish:next": "lerna publish --conventional-prerelease --force-publish --canary --no-git-tag-version --include-merged-tags --preid next --pre-dist-tag next --yes --registry https://registry.npmjs.org",

packages/common/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
},
2020
"scripts": {
2121
"build": "tsup --config ../../tsup.config.ts --tsconfig ../../tsconfig.tsup.json",
22-
"test": "vitest run --config ../../vitest.config.ts --coverage"
22+
"test": "vitest run --config ../../vitest.config.mts --coverage"
2323
},
2424
"dependencies": {
2525
"@sphereon/ssi-types": "0.34.1-feature.DIIPv4.245",

packages/oid4vci-common/lib/functions/TypeConversionUtils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export function getTypesFromCredentialSupported(
9393
credentialSupported.format === 'ldp_vc'
9494
) {
9595
types = getTypesFromObject(credentialSupported) ?? []
96-
} else if (credentialSupported.format === 'dc+sd-jwt'/* || credentialSupported.format === 'vc+sd-jwt'*/) { // TODO VCDM needs vc+sd-jwt back
96+
} else if (credentialSupported.format === 'dc+sd-jwt' || credentialSupported.format === 'vc+sd-jwt') {
9797
types = [credentialSupported.vct]
9898
} else if (credentialSupported.format === 'mso_mdoc') {
9999
types = [credentialSupported.doctype]

packages/oid4vci-common/lib/types/Authorization.types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ export interface AuthorizationDetailsJwtVcJsonLdAndLdpVc extends CommonAuthoriza
288288
}
289289

290290
export interface AuthorizationDetailsSdJwtVc extends CommonAuthorizationDetails {
291-
format: 'dc+sd-jwt'
291+
format: 'dc+sd-jwt' | 'vc+sd-jwt'
292292

293293
vct: string
294294
claims?: IssuerCredentialSubject

packages/oid4vci-common/lib/types/Generic.types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export interface ImageInfo {
2929
[key: string]: unknown
3030
}
3131

32-
export type OID4VCICredentialFormat = 'jwt_vc_json' | 'jwt_vc_json-ld' | 'ldp_vc' | 'dc+sd-jwt'| /*'vc+sd-jwt' |*/ 'jwt_vc' | 'mso_mdoc' // jwt_vc & vc+sd-jwt are added for backwards compat TODO SSISDK-36
32+
export type OID4VCICredentialFormat = 'jwt_vc_json' | 'jwt_vc_json-ld' | 'ldp_vc' | 'dc+sd-jwt'| 'vc+sd-jwt' | 'jwt_vc' | 'mso_mdoc' // jwt_vc & vc+sd-jwt are added for backwards compat TODO SSISDK-36
3333

3434
export const supportedOID4VCICredentialFormat: readonly (OID4VCICredentialFormat | string)[] = [
3535
'jwt_vc_json',
@@ -166,7 +166,7 @@ export interface CredentialSupportedJwtVcJson extends CommonCredentialSupported
166166
}
167167

168168
export interface CredentialSupportedSdJwtVc extends CommonCredentialSupported {
169-
format: 'dc+sd-jwt'
169+
format: 'dc+sd-jwt' | 'vc+sd-jwt' // TODO Separate CredentialSupportedSdJwtVc for vcdm2?
170170

171171
vct: string
172172
claims?: IssuerCredentialSubject

packages/siop-oid4vp/lib/__tests__/RP.request.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ describe('RP should', () => {
304304
expect(request.encodedUri).toMatch(expectedUri)
305305
expect(request.requestObjectJwt).toMatch(expectedJwtRegex)
306306

307-
const responseRedirectUri = rp.getResponseRedirectUri({ correlation_id: '1234', state: 'b32f0087fc9816eb813fd11f' })
307+
const responseRedirectUri = await rp.getResponseRedirectUri({ correlation_id: '1234', state: 'b32f0087fc9816eb813fd11f' })
308308
expect(responseRedirectUri).toBe('https://acme.com/1234?state=b32f0087fc9816eb813fd11f')
309309
})
310310
})

packages/siop-oid4vp/lib/rp/InMemoryRPSessionManager.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,19 @@ export class InMemoryRPSessionManager implements IRPSessionManager {
199199
queryId: event.queryId ?? this.queryIdMapping[event.correlationId],
200200
...(type === 'request' && { request: event.subject }),
201201
...(type === 'response' && { response: event.subject }),
202+
...(type === 'request' && event.responseRedirectURI && {responseRedirectURI: event.responseRedirectURI}),
202203
...(event.error && { error: event.error }),
203204
status,
204205
timestamp: event.timestamp,
205206
lastUpdated: event.timestamp,
206207
}
207208
let state: AuthorizationRequestState | AuthorizationResponseState
208209
if (type === 'request') {
209-
state = eventState as AuthorizationRequestState
210+
const prevState = this.authorizationRequests[event.correlationId]
211+
state = {
212+
...prevState,
213+
...eventState
214+
} as AuthorizationRequestState
210215
this.authorizationRequests[event.correlationId] = state
211216
this.updateMapping(this.nonceMapping, event, 'nonce', event.correlationId, true)
212217
this.updateMapping(this.stateMapping, event, 'state', event.correlationId, true)

packages/siop-oid4vp/lib/rp/RP.ts

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import {
3737
SupportedVersion,
3838
Verification,
3939
VerifiedAuthorizationResponse,
40-
CallbackOpts
40+
CallbackOpts, AuthorizationRequestState
4141
} from '../types'
4242

4343

@@ -93,7 +93,8 @@ export class RP {
9393
version?: SupportedVersion
9494
requestByReferenceURI?: string
9595
responseURI?: string
96-
responseURIType?: ResponseURIType
96+
responseURIType?: ResponseURIType,
97+
responseRedirectURI?: string
9798
}): Promise<AuthorizationRequest> {
9899
const authorizationRequestOpts = this.newAuthorizationRequestOpts(opts)
99100

@@ -131,23 +132,20 @@ export class RP {
131132
requestByReferenceURI?: string
132133
responseURI?: string
133134
responseURIType?: ResponseURIType
134-
callback?: CallbackOpts
135+
callback?: CallbackOpts,
136+
responseRedirectURI?: string
135137
}): Promise<URI> {
136138
const authorizationRequestOpts = this.newAuthorizationRequestOpts(opts)
137139

138140
try {
139-
if(opts.queryId && this._dcqlQueryLookupCallback) {
140-
const dcqlQuery:DcqlQuery = await this._dcqlQueryLookupCallback(opts.queryId)
141-
authorizationRequestOpts.payload.dcql_query = dcqlQuery
142-
}
143-
144141
const uri = await URI.fromOpts(authorizationRequestOpts)
145142
const authRequest = await AuthorizationRequest.fromOpts(authorizationRequestOpts)
146143
this.emitEvent(AuthorizationEvents.ON_AUTH_REQUEST_CREATED_SUCCESS, {
147144
correlationId: opts.correlationId,
148145
queryId: opts.queryId,
149146
subject: authRequest,
150-
callback: opts.callback
147+
callback: opts.callback,
148+
responseRedirectURI: opts.responseRedirectURI
151149
})
152150
return uri
153151
} catch (error) {
@@ -279,14 +277,35 @@ export class RP {
279277
return this._verifyResponseOptions
280278
}
281279

282-
public getResponseRedirectUri(mappings?: Record<string, string>): string | undefined {
283-
if (!this._responseRedirectUri) {
284-
return undefined
285-
}
280+
public async getResponseRedirectUri(mappings?: Record<string, string>): Promise<string | undefined> {
286281
if (!mappings) {
287282
return this._responseRedirectUri
288283
}
289-
return Object.entries(mappings).reduce((uri, [key, value]) => uri.replace(`:${key}`, value), this._responseRedirectUri)
284+
285+
// Attempt to retrieve state from session manager
286+
let state: AuthorizationRequestState | undefined
287+
if (this.sessionManager) {
288+
const correlationId = mappings['correlation_id'] ?? mappings['correlationId']
289+
290+
if (correlationId) {
291+
state = await this.sessionManager.getRequestStateByCorrelationId(correlationId, true)
292+
} else if (mappings['state']) {
293+
state = await this.sessionManager.getRequestStateByState(mappings['state'], true)
294+
}
295+
}
296+
297+
// Determine the redirect URI from state or fallback to default
298+
const redirectUri = state?.responseRedirectURI ?? this._responseRedirectUri
299+
300+
if (!redirectUri) {
301+
return undefined
302+
}
303+
304+
// Apply mappings to the redirect URI
305+
return Object.entries(mappings).reduce(
306+
(uri, [key, value]) => uri.replace(`:${key}`, value),
307+
redirectUri
308+
)
290309
}
291310

292311
private newAuthorizationRequestOpts(opts: {
@@ -458,6 +477,7 @@ export class RP {
458477
queryId?: string
459478
subject?: AuthorizationRequest | AuthorizationResponse | AuthorizationResponsePayload
460479
callback?: CallbackOpts
480+
responseRedirectURI?: string
461481
error?: Error
462482
},
463483
): void {

packages/siop-oid4vp/lib/types/Events.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,23 @@ export class AuthorizationEvent<T> {
3333
private readonly _timestamp: number
3434
private readonly _correlationId: string
3535
private readonly _queryId: string
36-
37-
public constructor(args: { correlationId: string; queryId?: string, subject?: T; callback?: CallbackOpts, error?: Error }) {
36+
private readonly _responseRedirectURI: string
37+
38+
public constructor(args: {
39+
correlationId: string;
40+
queryId?: string,
41+
subject?: T;
42+
callback?: CallbackOpts;
43+
responseRedirectURI?: string,
44+
error?: Error
45+
}) {
3846
//fixme: Create correlationId if not provided. Might need to be deferred to registry though
3947
this._correlationId = args.correlationId
4048
this._queryId = args.queryId
4149
this._timestamp = Date.now()
4250
this._subject = args.subject
4351
this._callback = args.callback
52+
this._responseRedirectURI = args.responseRedirectURI
4453
this._error = args.error
4554
}
4655

@@ -60,6 +69,10 @@ export class AuthorizationEvent<T> {
6069
return this._callback
6170
}
6271

72+
get responseRedirectURI(): string {
73+
return this._responseRedirectURI
74+
}
75+
6376
public hasError(): boolean {
6477
return !!this._error
6578
}

packages/siop-oid4vp/lib/types/SessionManager.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export interface AuthorizationRequestState {
88
request: AuthorizationRequest
99
status: AuthorizationRequestStateStatus
1010
callback?: CallbackOpts
11+
responseRedirectURI?: string
1112
timestamp: number
1213
lastUpdated: number
1314
error?: Error

0 commit comments

Comments
 (0)