@sphereon/oid4vci-client 0.15.1 → 0.15.2-next.38
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/AccessTokenClient.d.ts +7 -5
- package/dist/AccessTokenClient.d.ts.map +1 -1
- package/dist/AccessTokenClient.js +26 -5
- package/dist/AccessTokenClient.js.map +1 -1
- package/dist/AccessTokenClientV1_0_11.d.ts +7 -5
- package/dist/AccessTokenClientV1_0_11.d.ts.map +1 -1
- package/dist/AccessTokenClientV1_0_11.js +25 -5
- package/dist/AccessTokenClientV1_0_11.js.map +1 -1
- package/dist/AuthorizationCodeClient.d.ts.map +1 -1
- package/dist/AuthorizationCodeClient.js +11 -14
- package/dist/AuthorizationCodeClient.js.map +1 -1
- package/dist/AuthorizationCodeClientV1_0_11.js +1 -1
- package/dist/AuthorizationCodeClientV1_0_11.js.map +1 -1
- package/dist/CredentialRequestClient.d.ts +5 -3
- package/dist/CredentialRequestClient.d.ts.map +1 -1
- package/dist/CredentialRequestClient.js +22 -4
- package/dist/CredentialRequestClient.js.map +1 -1
- package/dist/CredentialRequestClientV1_0_11.d.ts +5 -3
- package/dist/CredentialRequestClientV1_0_11.d.ts.map +1 -1
- package/dist/CredentialRequestClientV1_0_11.js +22 -4
- package/dist/CredentialRequestClientV1_0_11.js.map +1 -1
- package/dist/OpenID4VCIClient.d.ts +2 -1
- package/dist/OpenID4VCIClient.d.ts.map +1 -1
- package/dist/OpenID4VCIClient.js.map +1 -1
- package/dist/OpenID4VCIClientV1_0_11.d.ts +2 -1
- package/dist/OpenID4VCIClientV1_0_11.d.ts.map +1 -1
- package/dist/OpenID4VCIClientV1_0_11.js.map +1 -1
- package/dist/OpenID4VCIClientV1_0_13.d.ts +2 -1
- package/dist/OpenID4VCIClientV1_0_13.d.ts.map +1 -1
- package/dist/OpenID4VCIClientV1_0_13.js.map +1 -1
- package/dist/ProofOfPossessionBuilder.d.ts +2 -1
- package/dist/ProofOfPossessionBuilder.d.ts.map +1 -1
- package/dist/ProofOfPossessionBuilder.js.map +1 -1
- package/dist/functions/AccessTokenUtil.d.ts.map +1 -1
- package/dist/functions/AccessTokenUtil.js +2 -2
- package/dist/functions/AccessTokenUtil.js.map +1 -1
- package/dist/functions/dpopUtil.d.ts +10 -0
- package/dist/functions/dpopUtil.d.ts.map +1 -0
- package/dist/functions/dpopUtil.js +30 -0
- package/dist/functions/dpopUtil.js.map +1 -0
- package/dist/functions/notifications.d.ts.map +1 -1
- package/dist/functions/notifications.js +3 -3
- package/dist/functions/notifications.js.map +1 -1
- package/lib/AccessTokenClient.ts +44 -7
- package/lib/AccessTokenClientV1_0_11.ts +43 -7
- package/lib/AuthorizationCodeClient.ts +11 -13
- package/lib/AuthorizationCodeClientV1_0_11.ts +1 -1
- package/lib/CredentialRequestClient.ts +38 -5
- package/lib/CredentialRequestClientV1_0_11.ts +38 -5
- package/lib/OpenID4VCIClient.ts +2 -2
- package/lib/OpenID4VCIClientV1_0_11.ts +1 -1
- package/lib/OpenID4VCIClientV1_0_13.ts +1 -1
- package/lib/ProofOfPossessionBuilder.ts +1 -1
- package/lib/__tests__/AccessTokenClient.spec.ts +4 -11
- package/lib/__tests__/OpenID4VCIClient.spec.ts +2 -23
- package/lib/__tests__/OpenID4VCIClientV1_0_13.spec.ts +2 -23
- package/lib/__tests__/SphereonE2E.spec.test.ts +3 -3
- package/lib/functions/AccessTokenUtil.ts +2 -2
- package/lib/functions/dpopUtil.ts +35 -0
- package/lib/functions/notifications.ts +2 -4
- package/package.json +4 -3
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.shouldRetryTokenRequestWithDPoPNonce = shouldRetryTokenRequestWithDPoPNonce;
|
|
4
|
+
exports.shouldRetryResourceRequestWithDPoPNonce = shouldRetryResourceRequestWithDPoPNonce;
|
|
5
|
+
const oid4vc_common_1 = require("@sphereon/oid4vc-common");
|
|
6
|
+
function shouldRetryTokenRequestWithDPoPNonce(response) {
|
|
7
|
+
if (!response.errorBody || response.errorBody.error !== oid4vc_common_1.dpopTokenRequestNonceError) {
|
|
8
|
+
return { ok: false };
|
|
9
|
+
}
|
|
10
|
+
const dPoPNonce = response.origResponse.headers.get('DPoP-Nonce');
|
|
11
|
+
if (!dPoPNonce) {
|
|
12
|
+
throw new Error('Missing required DPoP-Nonce header.');
|
|
13
|
+
}
|
|
14
|
+
return { ok: true, dpopNonce: dPoPNonce };
|
|
15
|
+
}
|
|
16
|
+
function shouldRetryResourceRequestWithDPoPNonce(response) {
|
|
17
|
+
if (!response.errorBody || response.origResponse.status !== 401) {
|
|
18
|
+
return { ok: false };
|
|
19
|
+
}
|
|
20
|
+
const wwwAuthenticateHeader = response.origResponse.headers.get('WWW-Authenticate');
|
|
21
|
+
if (!(wwwAuthenticateHeader === null || wwwAuthenticateHeader === void 0 ? void 0 : wwwAuthenticateHeader.includes(oid4vc_common_1.dpopTokenRequestNonceError))) {
|
|
22
|
+
return { ok: false };
|
|
23
|
+
}
|
|
24
|
+
const dPoPNonce = response.origResponse.headers.get('DPoP-Nonce');
|
|
25
|
+
if (!dPoPNonce) {
|
|
26
|
+
throw new Error('Missing required DPoP-Nonce header.');
|
|
27
|
+
}
|
|
28
|
+
return { ok: true, dpopNonce: dPoPNonce };
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=dpopUtil.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dpopUtil.js","sourceRoot":"","sources":["../../lib/functions/dpopUtil.ts"],"names":[],"mappings":";;AAKA,oFAWC;AAED,0FAgBC;AAlCD,2DAAqE;AAKrE,SAAgB,oCAAoC,CAAC,QAA0C;IAC7F,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS,CAAC,KAAK,KAAK,0CAA0B,EAAE,CAAC;QACnF,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAClE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAC5C,CAAC;AAED,SAAgB,uCAAuC,CAAC,QAA0C;IAChG,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,YAAY,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAChE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,MAAM,qBAAqB,GAAG,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACpF,IAAI,CAAC,CAAA,qBAAqB,aAArB,qBAAqB,uBAArB,qBAAqB,CAAE,QAAQ,CAAC,0CAA0B,CAAC,CAAA,EAAE,CAAC;QACjE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAClE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAC5C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../../lib/functions/notifications.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,mBAAmB,EAAE,kBAAkB,EAAQ,MAAM,0BAA0B,CAAC;AAEpH,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,wBAAsB,gBAAgB,CACpC,qBAAqB,EAAE,OAAO,CAAC,qBAAqB,CAAC,EACrD,OAAO,EAAE,mBAAmB,EAC5B,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC,
|
|
1
|
+
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../../lib/functions/notifications.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,mBAAmB,EAAE,kBAAkB,EAAQ,MAAM,0BAA0B,CAAC;AAEpH,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,wBAAsB,gBAAgB,CACpC,qBAAqB,EAAE,OAAO,CAAC,qBAAqB,CAAC,EACrD,OAAO,EAAE,mBAAmB,EAC5B,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAoB7B"}
|
|
@@ -14,7 +14,7 @@ const oid4vci_common_1 = require("@sphereon/oid4vci-common");
|
|
|
14
14
|
const types_1 = require("../types");
|
|
15
15
|
function sendNotification(credentialRequestOpts, request, accessToken) {
|
|
16
16
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
-
var _a
|
|
17
|
+
var _a;
|
|
18
18
|
types_1.LOG.info(`Sending status notification event '${request.event}' for id ${request.notification_id}`);
|
|
19
19
|
if (!credentialRequestOpts.notificationEndpoint) {
|
|
20
20
|
throw Error(`Cannot send notification when no notification endpoint is provided`);
|
|
@@ -24,10 +24,10 @@ function sendNotification(credentialRequestOpts, request, accessToken) {
|
|
|
24
24
|
const error = ((_a = response.errorBody) === null || _a === void 0 ? void 0 : _a.error) !== undefined;
|
|
25
25
|
const result = {
|
|
26
26
|
error,
|
|
27
|
-
response: error ?
|
|
27
|
+
response: error ? response.errorBody : undefined,
|
|
28
28
|
};
|
|
29
29
|
if (error) {
|
|
30
|
-
types_1.LOG.warning(`Notification endpoint returned an error for event '${request.event}' and id ${request.notification_id}: ${
|
|
30
|
+
types_1.LOG.warning(`Notification endpoint returned an error for event '${request.event}' and id ${request.notification_id}: ${response.errorBody}`);
|
|
31
31
|
}
|
|
32
32
|
else {
|
|
33
33
|
types_1.LOG.debug(`Notification endpoint returned success for event '${request.event}' and id ${request.notification_id}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../lib/functions/notifications.ts"],"names":[],"mappings":";;;;;;;;;;;AAKA,
|
|
1
|
+
{"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../lib/functions/notifications.ts"],"names":[],"mappings":";;;;;;;;;;;AAKA,4CAwBC;AA7BD,6DAAoH;AAGpH,oCAA+B;AAE/B,SAAsB,gBAAgB,CACpC,qBAAqD,EACrD,OAA4B,EAC5B,WAAoB;;;QAEpB,WAAG,CAAC,IAAI,CAAC,sCAAsC,OAAO,CAAC,KAAK,YAAY,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;QACnG,IAAI,CAAC,qBAAqB,CAAC,oBAAoB,EAAE,CAAC;YAChD,MAAM,KAAK,CAAC,oEAAoE,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,KAAK,GAAG,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,qBAAqB,CAAC,KAAK,CAAC;QACzD,MAAM,QAAQ,GAAG,MAAM,IAAA,qBAAI,EAA4B,qBAAqB,CAAC,oBAAoB,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,oBACrH,CAAC,KAAK,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EACpC,CAAC;QACH,MAAM,KAAK,GAAG,CAAA,MAAA,QAAQ,CAAC,SAAS,0CAAE,KAAK,MAAK,SAAS,CAAC;QACtD,MAAM,MAAM,GAAG;YACb,KAAK;YACL,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;SACjD,CAAC;QACF,IAAI,KAAK,EAAE,CAAC;YACV,WAAG,CAAC,OAAO,CAAC,sDAAsD,OAAO,CAAC,KAAK,YAAY,OAAO,CAAC,eAAe,KAAK,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;QAC/I,CAAC;aAAM,CAAC;YACN,WAAG,CAAC,KAAK,CAAC,qDAAqD,OAAO,CAAC,KAAK,YAAY,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;QACrH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CAAA"}
|
package/lib/AccessTokenClient.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createDPoP, CreateDPoPClientOpts, getCreateDPoPOptions } from '@sphereon/oid4vc-common';
|
|
1
2
|
import {
|
|
2
3
|
AccessTokenRequest,
|
|
3
4
|
AccessTokenRequestOpts,
|
|
@@ -6,6 +7,7 @@ import {
|
|
|
6
7
|
AuthorizationServerOpts,
|
|
7
8
|
AuthzFlowType,
|
|
8
9
|
convertJsonToURI,
|
|
10
|
+
DPoPResponseParams,
|
|
9
11
|
EndpointMetadata,
|
|
10
12
|
formPost,
|
|
11
13
|
getIssuerFromCredentialOfferPayload,
|
|
@@ -24,11 +26,12 @@ import { ObjectUtils } from '@sphereon/ssi-types';
|
|
|
24
26
|
|
|
25
27
|
import { MetadataClientV1_0_13 } from './MetadataClientV1_0_13';
|
|
26
28
|
import { createJwtBearerClientAssertion } from './functions';
|
|
29
|
+
import { shouldRetryTokenRequestWithDPoPNonce } from './functions/dpopUtil';
|
|
27
30
|
import { LOG } from './types';
|
|
28
31
|
|
|
29
32
|
export class AccessTokenClient {
|
|
30
|
-
public async acquireAccessToken(opts: AccessTokenRequestOpts): Promise<OpenIDResponse<AccessTokenResponse>> {
|
|
31
|
-
const { asOpts, pin, codeVerifier, code, redirectUri, metadata } = opts;
|
|
33
|
+
public async acquireAccessToken(opts: AccessTokenRequestOpts): Promise<OpenIDResponse<AccessTokenResponse, DPoPResponseParams>> {
|
|
34
|
+
const { asOpts, pin, codeVerifier, code, redirectUri, metadata, createDPoPOpts } = opts;
|
|
32
35
|
|
|
33
36
|
const credentialOffer = opts.credentialOffer ? await assertedUniformCredentialOffer(opts.credentialOffer) : undefined;
|
|
34
37
|
const pinMetadata: TxCodeAndPinRequired | undefined = credentialOffer && this.getPinMetadata(credentialOffer.credential_offer);
|
|
@@ -59,6 +62,7 @@ export class AccessTokenClient {
|
|
|
59
62
|
metadata,
|
|
60
63
|
asOpts,
|
|
61
64
|
issuerOpts,
|
|
65
|
+
createDPoPOpts: createDPoPOpts,
|
|
62
66
|
});
|
|
63
67
|
}
|
|
64
68
|
|
|
@@ -68,13 +72,15 @@ export class AccessTokenClient {
|
|
|
68
72
|
metadata,
|
|
69
73
|
asOpts,
|
|
70
74
|
issuerOpts,
|
|
75
|
+
createDPoPOpts,
|
|
71
76
|
}: {
|
|
72
77
|
accessTokenRequest: AccessTokenRequest;
|
|
73
78
|
pinMetadata?: TxCodeAndPinRequired;
|
|
74
79
|
metadata?: EndpointMetadata;
|
|
75
80
|
asOpts?: AuthorizationServerOpts;
|
|
76
81
|
issuerOpts?: IssuerOpts;
|
|
77
|
-
|
|
82
|
+
createDPoPOpts?: CreateDPoPClientOpts;
|
|
83
|
+
}): Promise<OpenIDResponse<AccessTokenResponse, DPoPResponseParams>> {
|
|
78
84
|
this.validate(accessTokenRequest, pinMetadata);
|
|
79
85
|
|
|
80
86
|
const requestTokenURL = AccessTokenClient.determineTokenURL({
|
|
@@ -87,10 +93,34 @@ export class AccessTokenClient {
|
|
|
87
93
|
: undefined,
|
|
88
94
|
});
|
|
89
95
|
|
|
90
|
-
|
|
96
|
+
const useDpop = createDPoPOpts?.dPoPSigningAlgValuesSupported && createDPoPOpts.dPoPSigningAlgValuesSupported.length > 0;
|
|
97
|
+
let dPoP = useDpop ? await createDPoP(getCreateDPoPOptions(createDPoPOpts, requestTokenURL)) : undefined;
|
|
98
|
+
|
|
99
|
+
let response = await this.sendAuthCode(requestTokenURL, accessTokenRequest, dPoP ? { headers: { dpop: dPoP } } : undefined);
|
|
100
|
+
|
|
101
|
+
let nextDPoPNonce = createDPoPOpts?.jwtPayloadProps.nonce;
|
|
102
|
+
const retryWithNonce = shouldRetryTokenRequestWithDPoPNonce(response);
|
|
103
|
+
if (retryWithNonce.ok && createDPoPOpts) {
|
|
104
|
+
createDPoPOpts.jwtPayloadProps.nonce = retryWithNonce.dpopNonce;
|
|
105
|
+
|
|
106
|
+
dPoP = await createDPoP(getCreateDPoPOptions(createDPoPOpts, requestTokenURL));
|
|
107
|
+
response = await this.sendAuthCode(requestTokenURL, accessTokenRequest, dPoP ? { headers: { dpop: dPoP } } : undefined);
|
|
108
|
+
const successDPoPNonce = response.origResponse.headers.get('DPoP-Nonce');
|
|
109
|
+
|
|
110
|
+
nextDPoPNonce = successDPoPNonce ?? retryWithNonce.dpopNonce;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (response.successBody && createDPoPOpts && response.successBody.token_type !== 'DPoP') {
|
|
114
|
+
throw new Error('Invalid token type returned. Expected DPoP. Received: ' + response.successBody.token_type);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
...response,
|
|
119
|
+
params: { ...(nextDPoPNonce && { dpop: { dpopNonce: nextDPoPNonce } }) },
|
|
120
|
+
};
|
|
91
121
|
}
|
|
92
122
|
|
|
93
|
-
public async createAccessTokenRequest(opts: AccessTokenRequestOpts): Promise<AccessTokenRequest> {
|
|
123
|
+
public async createAccessTokenRequest(opts: Omit<AccessTokenRequestOpts, 'createDPoPOpts'>): Promise<AccessTokenRequest> {
|
|
94
124
|
const { asOpts, pin, codeVerifier, code, redirectUri } = opts;
|
|
95
125
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
96
126
|
// @ts-ignore
|
|
@@ -105,6 +135,7 @@ export class AccessTokenClient {
|
|
|
105
135
|
if (credentialOfferRequest?.supportedFlows.includes(AuthzFlowType.PRE_AUTHORIZED_CODE_FLOW)) {
|
|
106
136
|
this.assertAlphanumericPin(opts.pinMetadata, pin);
|
|
107
137
|
request.user_pin = pin;
|
|
138
|
+
request.tx_code = pin;
|
|
108
139
|
|
|
109
140
|
request.grant_type = GrantTypes.PRE_AUTHORIZED_CODE;
|
|
110
141
|
// we actually know it is there because of the isPreAuthCode call
|
|
@@ -221,8 +252,14 @@ export class AccessTokenClient {
|
|
|
221
252
|
}
|
|
222
253
|
}
|
|
223
254
|
|
|
224
|
-
private async sendAuthCode(
|
|
225
|
-
|
|
255
|
+
private async sendAuthCode(
|
|
256
|
+
requestTokenURL: string,
|
|
257
|
+
accessTokenRequest: AccessTokenRequest,
|
|
258
|
+
opts?: { headers?: Record<string, string> },
|
|
259
|
+
): Promise<OpenIDResponse<AccessTokenResponse, DPoPResponseParams>> {
|
|
260
|
+
return await formPost(requestTokenURL, convertJsonToURI(accessTokenRequest, { mode: JsonURIMode.X_FORM_WWW_URLENCODED }), {
|
|
261
|
+
customHeaders: opts?.headers ? opts.headers : undefined,
|
|
262
|
+
});
|
|
226
263
|
}
|
|
227
264
|
|
|
228
265
|
public static determineTokenURL({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createDPoP, CreateDPoPClientOpts, getCreateDPoPOptions } from '@sphereon/oid4vc-common';
|
|
1
2
|
import {
|
|
2
3
|
AccessTokenRequest,
|
|
3
4
|
AccessTokenRequestOpts,
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
convertJsonToURI,
|
|
9
10
|
CredentialOfferV1_0_11,
|
|
10
11
|
CredentialOfferV1_0_13,
|
|
12
|
+
DPoPResponseParams,
|
|
11
13
|
EndpointMetadata,
|
|
12
14
|
formPost,
|
|
13
15
|
getIssuerFromCredentialOfferPayload,
|
|
@@ -27,12 +29,13 @@ import Debug from 'debug';
|
|
|
27
29
|
|
|
28
30
|
import { MetadataClientV1_0_13 } from './MetadataClientV1_0_13';
|
|
29
31
|
import { createJwtBearerClientAssertion } from './functions';
|
|
32
|
+
import { shouldRetryTokenRequestWithDPoPNonce } from './functions/dpopUtil';
|
|
30
33
|
|
|
31
34
|
const debug = Debug('sphereon:oid4vci:token');
|
|
32
35
|
|
|
33
36
|
export class AccessTokenClientV1_0_11 {
|
|
34
|
-
public async acquireAccessToken(opts: AccessTokenRequestOpts): Promise<OpenIDResponse<AccessTokenResponse>> {
|
|
35
|
-
const { asOpts, pin, codeVerifier, code, redirectUri, metadata } = opts;
|
|
37
|
+
public async acquireAccessToken(opts: AccessTokenRequestOpts): Promise<OpenIDResponse<AccessTokenResponse, DPoPResponseParams>> {
|
|
38
|
+
const { asOpts, pin, codeVerifier, code, redirectUri, metadata, createDPoPOpts } = opts;
|
|
36
39
|
|
|
37
40
|
const credentialOffer = opts.credentialOffer ? await assertedUniformCredentialOffer(opts.credentialOffer) : undefined;
|
|
38
41
|
const isPinRequired = credentialOffer && this.isPinRequiredValue(credentialOffer.credential_offer);
|
|
@@ -63,6 +66,7 @@ export class AccessTokenClientV1_0_11 {
|
|
|
63
66
|
metadata,
|
|
64
67
|
asOpts,
|
|
65
68
|
issuerOpts,
|
|
69
|
+
createDPoPOpts,
|
|
66
70
|
});
|
|
67
71
|
}
|
|
68
72
|
|
|
@@ -71,6 +75,7 @@ export class AccessTokenClientV1_0_11 {
|
|
|
71
75
|
isPinRequired,
|
|
72
76
|
metadata,
|
|
73
77
|
asOpts,
|
|
78
|
+
createDPoPOpts,
|
|
74
79
|
issuerOpts,
|
|
75
80
|
}: {
|
|
76
81
|
accessTokenRequest: AccessTokenRequest;
|
|
@@ -78,7 +83,8 @@ export class AccessTokenClientV1_0_11 {
|
|
|
78
83
|
metadata?: EndpointMetadata;
|
|
79
84
|
asOpts?: AuthorizationServerOpts;
|
|
80
85
|
issuerOpts?: IssuerOpts;
|
|
81
|
-
|
|
86
|
+
createDPoPOpts?: CreateDPoPClientOpts;
|
|
87
|
+
}): Promise<OpenIDResponse<AccessTokenResponse, DPoPResponseParams>> {
|
|
82
88
|
this.validate(accessTokenRequest, isPinRequired);
|
|
83
89
|
|
|
84
90
|
const requestTokenURL = AccessTokenClientV1_0_11.determineTokenURL({
|
|
@@ -91,10 +97,34 @@ export class AccessTokenClientV1_0_11 {
|
|
|
91
97
|
: undefined,
|
|
92
98
|
});
|
|
93
99
|
|
|
94
|
-
|
|
100
|
+
const useDpop = createDPoPOpts?.dPoPSigningAlgValuesSupported && createDPoPOpts.dPoPSigningAlgValuesSupported.length > 0;
|
|
101
|
+
let dPoP = useDpop ? await createDPoP(getCreateDPoPOptions(createDPoPOpts, requestTokenURL)) : undefined;
|
|
102
|
+
|
|
103
|
+
let response = await this.sendAuthCode(requestTokenURL, accessTokenRequest, dPoP ? { headers: { dpop: dPoP } } : undefined);
|
|
104
|
+
|
|
105
|
+
let nextDPoPNonce = createDPoPOpts?.jwtPayloadProps.nonce;
|
|
106
|
+
const retryWithNonce = shouldRetryTokenRequestWithDPoPNonce(response);
|
|
107
|
+
if (retryWithNonce.ok && createDPoPOpts) {
|
|
108
|
+
createDPoPOpts.jwtPayloadProps.nonce = retryWithNonce.dpopNonce;
|
|
109
|
+
|
|
110
|
+
dPoP = await createDPoP(getCreateDPoPOptions(createDPoPOpts, requestTokenURL));
|
|
111
|
+
response = await this.sendAuthCode(requestTokenURL, accessTokenRequest, dPoP ? { headers: { dpop: dPoP } } : undefined);
|
|
112
|
+
const successDPoPNonce = response.origResponse.headers.get('DPoP-Nonce');
|
|
113
|
+
|
|
114
|
+
nextDPoPNonce = successDPoPNonce ?? retryWithNonce.dpopNonce;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (response.successBody && createDPoPOpts && response.successBody.token_type !== 'DPoP') {
|
|
118
|
+
throw new Error('Invalid token type returned. Expected DPoP. Received: ' + response.successBody.token_type);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
...response,
|
|
123
|
+
params: { ...(nextDPoPNonce && { dpop: { dpopNonce: nextDPoPNonce } }) },
|
|
124
|
+
};
|
|
95
125
|
}
|
|
96
126
|
|
|
97
|
-
public async createAccessTokenRequest(opts: AccessTokenRequestOpts): Promise<AccessTokenRequest> {
|
|
127
|
+
public async createAccessTokenRequest(opts: Omit<AccessTokenRequestOpts, 'createDPoPOpts'>): Promise<AccessTokenRequest> {
|
|
98
128
|
const { asOpts, pin, codeVerifier, code, redirectUri } = opts;
|
|
99
129
|
const credentialOfferRequest = opts.credentialOffer
|
|
100
130
|
? await toUniformCredentialOfferRequest(opts.credentialOffer as CredentialOfferV1_0_11 | CredentialOfferV1_0_13)
|
|
@@ -204,8 +234,14 @@ export class AccessTokenClientV1_0_11 {
|
|
|
204
234
|
}
|
|
205
235
|
}
|
|
206
236
|
|
|
207
|
-
private async sendAuthCode(
|
|
208
|
-
|
|
237
|
+
private async sendAuthCode(
|
|
238
|
+
requestTokenURL: string,
|
|
239
|
+
accessTokenRequest: AccessTokenRequest,
|
|
240
|
+
opts?: { headers?: Record<string, string> },
|
|
241
|
+
): Promise<OpenIDResponse<AccessTokenResponse>> {
|
|
242
|
+
return await formPost(requestTokenURL, convertJsonToURI(accessTokenRequest, { mode: JsonURIMode.X_FORM_WWW_URLENCODED }), {
|
|
243
|
+
customHeaders: opts?.headers ? opts.headers : undefined,
|
|
244
|
+
});
|
|
209
245
|
}
|
|
210
246
|
|
|
211
247
|
public static determineTokenURL({
|
|
@@ -113,13 +113,16 @@ export const createAuthorizationRequestUrl = async ({
|
|
|
113
113
|
const { redirectUri, requestObjectOpts = { requestObjectMode: CreateRequestObjectMode.NONE } } = authorizationRequest;
|
|
114
114
|
const client_id = clientId ?? authorizationRequest.clientId;
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
const
|
|
116
|
+
// Authorization server metadata takes precedence
|
|
117
|
+
const authorizationMetadata = endpointMetadata.authorizationServerMetadata ?? endpointMetadata.credentialIssuerMetadata;
|
|
118
|
+
|
|
119
|
+
let { authorizationDetails } = authorizationRequest;
|
|
120
|
+
const parMode = authorizationMetadata?.require_pushed_authorization_requests
|
|
118
121
|
? PARMode.REQUIRE
|
|
119
|
-
: authorizationRequest.parMode ?? (client_id ? PARMode.AUTO : PARMode.NEVER);
|
|
122
|
+
: (authorizationRequest.parMode ?? (client_id ? PARMode.AUTO : PARMode.NEVER));
|
|
120
123
|
// Scope and authorization_details can be used in the same authorization request
|
|
121
124
|
// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rar-23#name-relationship-to-scope-param
|
|
122
|
-
if (!scope && !authorizationDetails) {
|
|
125
|
+
if (!authorizationRequest.scope && !authorizationDetails) {
|
|
123
126
|
if (!credentialOffer) {
|
|
124
127
|
throw Error('Please provide a scope or authorization_details if no credential offer is present');
|
|
125
128
|
}
|
|
@@ -177,12 +180,7 @@ export const createAuthorizationRequestUrl = async ({
|
|
|
177
180
|
if (!endpointMetadata?.authorization_endpoint) {
|
|
178
181
|
throw Error('Server metadata does not contain authorization endpoint');
|
|
179
182
|
}
|
|
180
|
-
const parEndpoint =
|
|
181
|
-
|
|
182
|
-
// add 'openid' scope if not present
|
|
183
|
-
if (!scope?.includes('openid')) {
|
|
184
|
-
scope = ['openid', scope].filter((s) => !!s).join(' ');
|
|
185
|
-
}
|
|
183
|
+
const parEndpoint = authorizationMetadata?.pushed_authorization_request_endpoint;
|
|
186
184
|
|
|
187
185
|
let queryObj: Record<string, any> | PushedAuthorizationResponse = {
|
|
188
186
|
response_type: ResponseType.AUTH_CODE,
|
|
@@ -194,7 +192,7 @@ export const createAuthorizationRequestUrl = async ({
|
|
|
194
192
|
...(redirectUri && { redirect_uri: redirectUri }),
|
|
195
193
|
...(client_id && { client_id }),
|
|
196
194
|
...(credentialOffer?.issuerState && { issuer_state: credentialOffer.issuerState }),
|
|
197
|
-
scope,
|
|
195
|
+
scope: authorizationRequest.scope,
|
|
198
196
|
};
|
|
199
197
|
|
|
200
198
|
if (!parEndpoint && parMode === PARMode.REQUIRE) {
|
|
@@ -210,11 +208,11 @@ export const createAuthorizationRequestUrl = async ({
|
|
|
210
208
|
{ contentType: 'application/x-www-form-urlencoded', accept: 'application/json' },
|
|
211
209
|
);
|
|
212
210
|
if (parResponse.errorBody || !parResponse.successBody) {
|
|
213
|
-
console.log(JSON.stringify(parResponse.errorBody));
|
|
214
|
-
console.log('Falling back to regular request URI, since PAR failed');
|
|
215
211
|
if (parMode === PARMode.REQUIRE) {
|
|
216
212
|
throw Error(`PAR error: ${parResponse.origResponse.statusText}`);
|
|
217
213
|
}
|
|
214
|
+
|
|
215
|
+
debug('Falling back to regular request URI, since PAR failed', JSON.stringify(parResponse.errorBody));
|
|
218
216
|
} else {
|
|
219
217
|
debug(`PAR response: ${JSON.stringify(parResponse.successBody, null, 2)}`);
|
|
220
218
|
queryObj = { /*response_type: ResponseType.AUTH_CODE,*/ client_id, request_uri: parResponse.successBody.request_uri };
|
|
@@ -40,7 +40,7 @@ export const createAuthorizationRequestUrlV1_0_11 = async ({
|
|
|
40
40
|
|
|
41
41
|
const parMode = endpointMetadata?.credentialIssuerMetadata?.require_pushed_authorization_requests
|
|
42
42
|
? PARMode.REQUIRE
|
|
43
|
-
: authorizationRequest.parMode ?? PARMode.AUTO;
|
|
43
|
+
: (authorizationRequest.parMode ?? PARMode.AUTO);
|
|
44
44
|
// Scope and authorization_details can be used in the same authorization request
|
|
45
45
|
// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rar-23#name-relationship-to-scope-param
|
|
46
46
|
if (!scope && !authorizationDetails) {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { createDPoP, CreateDPoPClientOpts, getCreateDPoPOptions } from '@sphereon/oid4vc-common';
|
|
1
2
|
import {
|
|
2
3
|
acquireDeferredCredential,
|
|
3
4
|
CredentialRequestV1_0_13,
|
|
4
5
|
CredentialResponse,
|
|
6
|
+
DPoPResponseParams,
|
|
5
7
|
getCredentialRequestForVersion,
|
|
6
8
|
getUniformFormat,
|
|
7
9
|
isDeferredCredentialResponse,
|
|
@@ -21,6 +23,7 @@ import Debug from 'debug';
|
|
|
21
23
|
import { CredentialRequestClientBuilderV1_0_11 } from './CredentialRequestClientBuilderV1_0_11';
|
|
22
24
|
import { CredentialRequestClientBuilderV1_0_13 } from './CredentialRequestClientBuilderV1_0_13';
|
|
23
25
|
import { ProofOfPossessionBuilder } from './ProofOfPossessionBuilder';
|
|
26
|
+
import { shouldRetryResourceRequestWithDPoPNonce } from './functions/dpopUtil';
|
|
24
27
|
|
|
25
28
|
const debug = Debug('sphereon:oid4vci:credential');
|
|
26
29
|
|
|
@@ -89,7 +92,8 @@ export class CredentialRequestClient {
|
|
|
89
92
|
context?: string[];
|
|
90
93
|
format?: CredentialFormat | OID4VCICredentialFormat;
|
|
91
94
|
subjectIssuance?: ExperimentalSubjectIssuance;
|
|
92
|
-
|
|
95
|
+
createDPoPOpts?: CreateDPoPClientOpts;
|
|
96
|
+
}): Promise<OpenIDResponse<CredentialResponse, DPoPResponseParams> & { access_token: string }> {
|
|
93
97
|
const { credentialIdentifier, credentialTypes, proofInput, format, context, subjectIssuance } = opts;
|
|
94
98
|
|
|
95
99
|
const request = await this.createCredentialRequest({
|
|
@@ -101,12 +105,13 @@ export class CredentialRequestClient {
|
|
|
101
105
|
credentialIdentifier,
|
|
102
106
|
subjectIssuance,
|
|
103
107
|
});
|
|
104
|
-
return await this.acquireCredentialsUsingRequest(request);
|
|
108
|
+
return await this.acquireCredentialsUsingRequest(request, opts.createDPoPOpts);
|
|
105
109
|
}
|
|
106
110
|
|
|
107
111
|
public async acquireCredentialsUsingRequest(
|
|
108
112
|
uniformRequest: UniformCredentialRequest,
|
|
109
|
-
|
|
113
|
+
createDPoPOpts?: CreateDPoPClientOpts,
|
|
114
|
+
): Promise<OpenIDResponse<CredentialResponse, DPoPResponseParams> & { access_token: string }> {
|
|
110
115
|
if (this.version() < OpenId4VCIVersion.VER_1_0_13) {
|
|
111
116
|
throw new Error('Versions below v1.0.13 (draft 13) are not supported by the V13 credential request client.');
|
|
112
117
|
}
|
|
@@ -119,9 +124,33 @@ export class CredentialRequestClient {
|
|
|
119
124
|
debug(`Acquiring credential(s) from: ${credentialEndpoint}`);
|
|
120
125
|
debug(`request\n: ${JSON.stringify(request, null, 2)}`);
|
|
121
126
|
const requestToken: string = this.credentialRequestOpts.token;
|
|
122
|
-
|
|
127
|
+
|
|
128
|
+
let dPoP = createDPoPOpts ? await createDPoP(getCreateDPoPOptions(createDPoPOpts, credentialEndpoint, { accessToken: requestToken })) : undefined;
|
|
129
|
+
|
|
130
|
+
let response = (await post(credentialEndpoint, JSON.stringify(request), {
|
|
131
|
+
bearerToken: requestToken,
|
|
132
|
+
customHeaders: { ...(dPoP && { dpop: dPoP }) },
|
|
133
|
+
})) as OpenIDResponse<CredentialResponse> & {
|
|
123
134
|
access_token: string;
|
|
124
135
|
};
|
|
136
|
+
|
|
137
|
+
let nextDPoPNonce = createDPoPOpts?.jwtPayloadProps.nonce;
|
|
138
|
+
const retryWithNonce = shouldRetryResourceRequestWithDPoPNonce(response);
|
|
139
|
+
if (retryWithNonce.ok && createDPoPOpts) {
|
|
140
|
+
createDPoPOpts.jwtPayloadProps.nonce = retryWithNonce.dpopNonce;
|
|
141
|
+
dPoP = await createDPoP(getCreateDPoPOptions(createDPoPOpts, credentialEndpoint, { accessToken: requestToken }));
|
|
142
|
+
|
|
143
|
+
response = (await post(credentialEndpoint, JSON.stringify(request), {
|
|
144
|
+
bearerToken: requestToken,
|
|
145
|
+
customHeaders: { ...(createDPoPOpts && { dpop: dPoP }) },
|
|
146
|
+
})) as OpenIDResponse<CredentialResponse> & {
|
|
147
|
+
access_token: string;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const successDPoPNonce = response.origResponse.headers.get('DPoP-Nonce');
|
|
151
|
+
nextDPoPNonce = successDPoPNonce ?? retryWithNonce.dpopNonce;
|
|
152
|
+
}
|
|
153
|
+
|
|
125
154
|
this._isDeferred = isDeferredCredentialResponse(response);
|
|
126
155
|
if (this.isDeferred() && this.credentialRequestOpts.deferredCredentialAwait && response.successBody) {
|
|
127
156
|
response = await this.acquireDeferredCredential(response.successBody, { bearerToken: this.credentialRequestOpts.token });
|
|
@@ -134,7 +163,11 @@ export class CredentialRequestClient {
|
|
|
134
163
|
}
|
|
135
164
|
}
|
|
136
165
|
debug(`Credential endpoint ${credentialEndpoint} response:\r\n${JSON.stringify(response, null, 2)}`);
|
|
137
|
-
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
...response,
|
|
169
|
+
params: { ...(nextDPoPNonce && { dpop: { dpopNonce: nextDPoPNonce } }) },
|
|
170
|
+
};
|
|
138
171
|
}
|
|
139
172
|
|
|
140
173
|
public async acquireDeferredCredential(
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { createDPoP, CreateDPoPClientOpts, getCreateDPoPOptions } from '@sphereon/oid4vc-common';
|
|
1
2
|
import {
|
|
2
3
|
acquireDeferredCredential,
|
|
3
4
|
CredentialResponse,
|
|
5
|
+
DPoPResponseParams,
|
|
4
6
|
getCredentialRequestForVersion,
|
|
5
7
|
getUniformFormat,
|
|
6
8
|
isDeferredCredentialResponse,
|
|
@@ -20,6 +22,7 @@ import Debug from 'debug';
|
|
|
20
22
|
import { buildProof } from './CredentialRequestClient';
|
|
21
23
|
import { CredentialRequestClientBuilderV1_0_11 } from './CredentialRequestClientBuilderV1_0_11';
|
|
22
24
|
import { ProofOfPossessionBuilder } from './ProofOfPossessionBuilder';
|
|
25
|
+
import { shouldRetryResourceRequestWithDPoPNonce } from './functions/dpopUtil';
|
|
23
26
|
|
|
24
27
|
const debug = Debug('sphereon:oid4vci:credential');
|
|
25
28
|
|
|
@@ -64,16 +67,18 @@ export class CredentialRequestClientV1_0_11 {
|
|
|
64
67
|
credentialTypes?: string | string[];
|
|
65
68
|
context?: string[];
|
|
66
69
|
format?: CredentialFormat | OID4VCICredentialFormat;
|
|
67
|
-
|
|
70
|
+
createDPoPOpts?: CreateDPoPClientOpts;
|
|
71
|
+
}): Promise<OpenIDResponse<CredentialResponse, DPoPResponseParams> & { access_token: string }> {
|
|
68
72
|
const { credentialTypes, proofInput, format, context } = opts;
|
|
69
73
|
|
|
70
74
|
const request = await this.createCredentialRequest({ proofInput, credentialTypes, context, format, version: this.version() });
|
|
71
|
-
return await this.acquireCredentialsUsingRequest(request);
|
|
75
|
+
return await this.acquireCredentialsUsingRequest(request, opts.createDPoPOpts);
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
public async acquireCredentialsUsingRequest(
|
|
75
79
|
uniformRequest: UniformCredentialRequest,
|
|
76
|
-
|
|
80
|
+
createDPoPOpts?: CreateDPoPClientOpts,
|
|
81
|
+
): Promise<OpenIDResponse<CredentialResponse, DPoPResponseParams> & { access_token: string }> {
|
|
77
82
|
const request = getCredentialRequestForVersion(uniformRequest, this.version());
|
|
78
83
|
const credentialEndpoint: string = this.credentialRequestOpts.credentialEndpoint;
|
|
79
84
|
if (!isValidURL(credentialEndpoint)) {
|
|
@@ -83,9 +88,33 @@ export class CredentialRequestClientV1_0_11 {
|
|
|
83
88
|
debug(`Acquiring credential(s) from: ${credentialEndpoint}`);
|
|
84
89
|
debug(`request\n: ${JSON.stringify(request, null, 2)}`);
|
|
85
90
|
const requestToken: string = this.credentialRequestOpts.token;
|
|
86
|
-
|
|
91
|
+
|
|
92
|
+
let dPoP = createDPoPOpts ? await createDPoP(getCreateDPoPOptions(createDPoPOpts, credentialEndpoint, { accessToken: requestToken })) : undefined;
|
|
93
|
+
|
|
94
|
+
let response = (await post(credentialEndpoint, JSON.stringify(request), {
|
|
95
|
+
bearerToken: requestToken,
|
|
96
|
+
customHeaders: { ...(createDPoPOpts && { dpop: dPoP }) },
|
|
97
|
+
})) as OpenIDResponse<CredentialResponse> & {
|
|
87
98
|
access_token: string;
|
|
88
99
|
};
|
|
100
|
+
|
|
101
|
+
let nextDPoPNonce = createDPoPOpts?.jwtPayloadProps.nonce;
|
|
102
|
+
const retryWithNonce = shouldRetryResourceRequestWithDPoPNonce(response);
|
|
103
|
+
if (retryWithNonce.ok && createDPoPOpts) {
|
|
104
|
+
createDPoPOpts.jwtPayloadProps.nonce = retryWithNonce.dpopNonce;
|
|
105
|
+
dPoP = await createDPoP(getCreateDPoPOptions(createDPoPOpts, credentialEndpoint, { accessToken: requestToken }));
|
|
106
|
+
|
|
107
|
+
response = (await post(credentialEndpoint, JSON.stringify(request), {
|
|
108
|
+
bearerToken: requestToken,
|
|
109
|
+
customHeaders: { ...(createDPoPOpts && { dpop: dPoP }) },
|
|
110
|
+
})) as OpenIDResponse<CredentialResponse> & {
|
|
111
|
+
access_token: string;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const successDPoPNonce = response.origResponse.headers.get('DPoP-Nonce');
|
|
115
|
+
nextDPoPNonce = successDPoPNonce ?? retryWithNonce.dpopNonce;
|
|
116
|
+
}
|
|
117
|
+
|
|
89
118
|
this._isDeferred = isDeferredCredentialResponse(response);
|
|
90
119
|
if (this.isDeferred() && this.credentialRequestOpts.deferredCredentialAwait && response.successBody) {
|
|
91
120
|
response = await this.acquireDeferredCredential(response.successBody, { bearerToken: this.credentialRequestOpts.token });
|
|
@@ -93,7 +122,11 @@ export class CredentialRequestClientV1_0_11 {
|
|
|
93
122
|
response.access_token = requestToken;
|
|
94
123
|
|
|
95
124
|
debug(`Credential endpoint ${credentialEndpoint} response:\r\n${JSON.stringify(response, null, 2)}`);
|
|
96
|
-
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
...response,
|
|
128
|
+
params: { ...(nextDPoPNonce && { dpop: { dpopNonce: nextDPoPNonce } }) },
|
|
129
|
+
};
|
|
97
130
|
}
|
|
98
131
|
|
|
99
132
|
public async acquireDeferredCredential(
|
package/lib/OpenID4VCIClient.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { JWK } from '@sphereon/oid4vc-common';
|
|
1
2
|
import {
|
|
2
3
|
AccessTokenResponse,
|
|
3
4
|
Alg,
|
|
@@ -23,7 +24,6 @@ import {
|
|
|
23
24
|
getSupportedCredentials,
|
|
24
25
|
getTypesFromCredentialSupported,
|
|
25
26
|
getTypesFromObject,
|
|
26
|
-
JWK,
|
|
27
27
|
KID_JWK_X5C_ERROR,
|
|
28
28
|
NotificationRequest,
|
|
29
29
|
NotificationResult,
|
|
@@ -549,7 +549,7 @@ export class OpenID4VCIClient {
|
|
|
549
549
|
issuerSupportedFlowTypes(): AuthzFlowType[] {
|
|
550
550
|
return (
|
|
551
551
|
this.credentialOffer?.supportedFlows ??
|
|
552
|
-
(this._state.endpointMetadata?.credentialIssuerMetadata?.authorization_endpoint ?? this._state.endpointMetadata?.authorization_server
|
|
552
|
+
((this._state.endpointMetadata?.credentialIssuerMetadata?.authorization_endpoint ?? this._state.endpointMetadata?.authorization_server)
|
|
553
553
|
? [AuthzFlowType.AUTHORIZATION_CODE_FLOW]
|
|
554
554
|
: [])
|
|
555
555
|
);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { JWK } from '@sphereon/oid4vc-common';
|
|
1
2
|
import {
|
|
2
3
|
AccessTokenResponse,
|
|
3
4
|
Alg,
|
|
@@ -19,7 +20,6 @@ import {
|
|
|
19
20
|
getSupportedCredentials,
|
|
20
21
|
getTypesFromCredentialSupported,
|
|
21
22
|
getTypesFromObject,
|
|
22
|
-
JWK,
|
|
23
23
|
KID_JWK_X5C_ERROR,
|
|
24
24
|
OID4VCICredentialFormat,
|
|
25
25
|
OpenId4VCIVersion,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { JWK } from '@sphereon/oid4vc-common';
|
|
1
2
|
import {
|
|
2
3
|
AccessTokenResponse,
|
|
3
4
|
Alg,
|
|
@@ -17,7 +18,6 @@ import {
|
|
|
17
18
|
getIssuerFromCredentialOfferPayload,
|
|
18
19
|
getSupportedCredentials,
|
|
19
20
|
getTypesFromCredentialSupported,
|
|
20
|
-
JWK,
|
|
21
21
|
KID_JWK_X5C_ERROR,
|
|
22
22
|
NotificationRequest,
|
|
23
23
|
NotificationResult,
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AccessTokenRequest,
|
|
3
|
-
AccessTokenResponse,
|
|
4
|
-
GrantTypes,
|
|
5
|
-
OpenIDResponse,
|
|
6
|
-
PRE_AUTH_CODE_LITERAL,
|
|
7
|
-
WellKnownEndpoints,
|
|
8
|
-
} from '@sphereon/oid4vci-common';
|
|
1
|
+
import { AccessTokenRequest, AccessTokenResponse, GrantTypes, PRE_AUTH_CODE_LITERAL, WellKnownEndpoints } from '@sphereon/oid4vci-common';
|
|
9
2
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
10
3
|
// @ts-ignore
|
|
11
4
|
import nock from 'nock';
|
|
@@ -50,7 +43,7 @@ describe('AccessTokenClient should', () => {
|
|
|
50
43
|
};
|
|
51
44
|
nock(MOCK_URL).post(/.*/).reply(200, JSON.stringify(body));
|
|
52
45
|
|
|
53
|
-
const accessTokenResponse
|
|
46
|
+
const accessTokenResponse = await accessTokenClient.acquireAccessTokenUsingRequest({
|
|
54
47
|
accessTokenRequest,
|
|
55
48
|
pinMetadata: {
|
|
56
49
|
isPinRequired: true,
|
|
@@ -88,7 +81,7 @@ describe('AccessTokenClient should', () => {
|
|
|
88
81
|
};
|
|
89
82
|
nock(MOCK_URL).post(/.*/).reply(200, JSON.stringify(body));
|
|
90
83
|
|
|
91
|
-
const accessTokenResponse
|
|
84
|
+
const accessTokenResponse = await accessTokenClient.acquireAccessTokenUsingRequest({
|
|
92
85
|
accessTokenRequest,
|
|
93
86
|
asOpts: { as: MOCK_URL },
|
|
94
87
|
});
|
|
@@ -227,7 +220,7 @@ describe('AccessTokenClient should', () => {
|
|
|
227
220
|
.post(/.*/)
|
|
228
221
|
.reply(200, {});
|
|
229
222
|
|
|
230
|
-
const response
|
|
223
|
+
const response = await accessTokenClient.acquireAccessToken({
|
|
231
224
|
credentialOffer: INITIATION_TEST,
|
|
232
225
|
pin: '1234',
|
|
233
226
|
});
|