@sphereon/oid4vci-client 0.12.0 → 0.12.1-next.19
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.js +1 -1
- package/dist/AccessTokenClient.js.map +1 -1
- package/dist/AccessTokenClientV1_0_11.js +1 -1
- package/dist/AccessTokenClientV1_0_11.js.map +1 -1
- package/dist/AuthorizationCodeClient.d.ts.map +1 -1
- package/dist/AuthorizationCodeClient.js +4 -1
- package/dist/AuthorizationCodeClient.js.map +1 -1
- package/dist/CredentialRequestClient.d.ts +3 -2
- package/dist/CredentialRequestClient.d.ts.map +1 -1
- package/dist/CredentialRequestClient.js.map +1 -1
- package/dist/CredentialRequestClientBuilder.d.ts +7 -15
- package/dist/CredentialRequestClientBuilder.d.ts.map +1 -1
- package/dist/CredentialRequestClientBuilder.js +79 -55
- package/dist/CredentialRequestClientBuilder.js.map +1 -1
- package/dist/CredentialRequestClientBuilderV1_0_13.d.ts +51 -0
- package/dist/CredentialRequestClientBuilderV1_0_13.d.ts.map +1 -0
- package/dist/CredentialRequestClientBuilderV1_0_13.js +130 -0
- package/dist/CredentialRequestClientBuilderV1_0_13.js.map +1 -0
- package/dist/OpenID4VCIClient.d.ts +1 -0
- package/dist/OpenID4VCIClient.d.ts.map +1 -1
- package/dist/OpenID4VCIClient.js +5 -5
- package/dist/OpenID4VCIClient.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/lib/AccessTokenClient.ts +1 -1
- package/lib/AccessTokenClientV1_0_11.ts +1 -1
- package/lib/AuthorizationCodeClient.ts +7 -4
- package/lib/CredentialRequestClient.ts +3 -2
- package/lib/CredentialRequestClientBuilder.ts +98 -67
- package/lib/CredentialRequestClientBuilderV1_0_13.ts +173 -0
- package/lib/OpenID4VCIClient.ts +6 -4
- package/lib/__tests__/CredentialRequestClient.spec.ts +8 -13
- package/lib/__tests__/CredentialRequestClientBuilder.spec.ts +40 -2
- package/lib/__tests__/CredentialRequestClientV1_0_11.spec.ts +96 -0
- package/lib/__tests__/IT.spec.ts +148 -111
- package/lib/__tests__/MetadataMocks.ts +35 -0
- package/lib/__tests__/ProofOfPossessionBuilder.spec.ts +85 -0
- package/lib/__tests__/SdJwt.spec.ts +103 -0
- package/lib/index.ts +1 -0
- package/package.json +3 -3
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AccessTokenResponse,
|
|
3
|
+
CredentialIssuerMetadata,
|
|
3
4
|
CredentialIssuerMetadataV1_0_13,
|
|
4
|
-
CredentialOfferPayloadV1_0_13,
|
|
5
5
|
CredentialOfferRequestWithBaseUrl,
|
|
6
6
|
determineSpecVersionFromOffer,
|
|
7
7
|
EndpointMetadata,
|
|
8
8
|
ExperimentalSubjectIssuance,
|
|
9
|
-
getIssuerFromCredentialOfferPayload,
|
|
10
9
|
OID4VCICredentialFormat,
|
|
11
10
|
OpenId4VCIVersion,
|
|
12
11
|
UniformCredentialOfferRequest,
|
|
@@ -14,19 +13,21 @@ import {
|
|
|
14
13
|
import { CredentialFormat } from '@sphereon/ssi-types';
|
|
15
14
|
|
|
16
15
|
import { CredentialOfferClient } from './CredentialOfferClient';
|
|
17
|
-
import {
|
|
16
|
+
import { CredentialRequestClientBuilderV1_0_11 } from './CredentialRequestClientBuilderV1_0_11';
|
|
17
|
+
import { CredentialRequestClientBuilderV1_0_13 } from './CredentialRequestClientBuilderV1_0_13';
|
|
18
|
+
|
|
19
|
+
type CredentialRequestClientBuilderVersionSpecific = CredentialRequestClientBuilderV1_0_11 | CredentialRequestClientBuilderV1_0_13;
|
|
20
|
+
|
|
21
|
+
function isV1_0_13(builder: CredentialRequestClientBuilderVersionSpecific): builder is CredentialRequestClientBuilderV1_0_13 {
|
|
22
|
+
return (builder as CredentialRequestClientBuilderV1_0_13).withCredentialIdentifier !== undefined;
|
|
23
|
+
}
|
|
18
24
|
|
|
19
25
|
export class CredentialRequestClientBuilder {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
credentialTypes?: string[] = [];
|
|
26
|
-
format?: CredentialFormat | OID4VCICredentialFormat;
|
|
27
|
-
token?: string;
|
|
28
|
-
version?: OpenId4VCIVersion;
|
|
29
|
-
subjectIssuance?: ExperimentalSubjectIssuance;
|
|
26
|
+
private _builder: CredentialRequestClientBuilderVersionSpecific;
|
|
27
|
+
|
|
28
|
+
private constructor(builder: CredentialRequestClientBuilderVersionSpecific) {
|
|
29
|
+
this._builder = builder;
|
|
30
|
+
}
|
|
30
31
|
|
|
31
32
|
public static fromCredentialIssuer({
|
|
32
33
|
credentialIssuer,
|
|
@@ -41,25 +42,40 @@ export class CredentialRequestClientBuilder {
|
|
|
41
42
|
credentialIdentifier?: string;
|
|
42
43
|
credentialTypes?: string | string[];
|
|
43
44
|
}): CredentialRequestClientBuilder {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
45
|
+
const specVersion = version ?? OpenId4VCIVersion.VER_1_0_13;
|
|
46
|
+
let builder;
|
|
47
|
+
|
|
48
|
+
if (specVersion >= OpenId4VCIVersion.VER_1_0_13) {
|
|
49
|
+
builder = CredentialRequestClientBuilderV1_0_13.fromCredentialIssuer({
|
|
50
|
+
credentialIssuer,
|
|
51
|
+
metadata,
|
|
52
|
+
version,
|
|
53
|
+
credentialIdentifier,
|
|
54
|
+
credentialTypes,
|
|
55
|
+
});
|
|
56
|
+
} else {
|
|
57
|
+
if (!credentialTypes || credentialTypes.length === 0) {
|
|
58
|
+
throw new Error('CredentialTypes must be provided for v1_0_11');
|
|
59
|
+
}
|
|
60
|
+
builder = CredentialRequestClientBuilderV1_0_11.fromCredentialIssuer({
|
|
61
|
+
credentialIssuer,
|
|
62
|
+
metadata,
|
|
63
|
+
version,
|
|
64
|
+
credentialTypes,
|
|
65
|
+
});
|
|
56
66
|
}
|
|
57
|
-
|
|
67
|
+
|
|
68
|
+
return new CredentialRequestClientBuilder(builder);
|
|
58
69
|
}
|
|
59
70
|
|
|
60
71
|
public static async fromURI({ uri, metadata }: { uri: string; metadata?: EndpointMetadata }): Promise<CredentialRequestClientBuilder> {
|
|
61
72
|
const offer = await CredentialOfferClient.fromURI(uri);
|
|
62
|
-
return CredentialRequestClientBuilder.fromCredentialOfferRequest({
|
|
73
|
+
return CredentialRequestClientBuilder.fromCredentialOfferRequest({
|
|
74
|
+
request: offer,
|
|
75
|
+
...offer,
|
|
76
|
+
metadata,
|
|
77
|
+
version: offer.version,
|
|
78
|
+
});
|
|
63
79
|
}
|
|
64
80
|
|
|
65
81
|
public static fromCredentialOfferRequest(opts: {
|
|
@@ -69,24 +85,17 @@ export class CredentialRequestClientBuilder {
|
|
|
69
85
|
version?: OpenId4VCIVersion;
|
|
70
86
|
metadata?: EndpointMetadata;
|
|
71
87
|
}): CredentialRequestClientBuilder {
|
|
72
|
-
const { request
|
|
88
|
+
const { request } = opts;
|
|
73
89
|
const version = opts.version ?? request.version ?? determineSpecVersionFromOffer(request.original_credential_offer);
|
|
90
|
+
let builder;
|
|
91
|
+
|
|
74
92
|
if (version < OpenId4VCIVersion.VER_1_0_13) {
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const issuer = getIssuerFromCredentialOfferPayload(request.credential_offer) ?? (metadata?.issuer as string);
|
|
79
|
-
builder.withVersion(version);
|
|
80
|
-
builder.withCredentialEndpoint(metadata?.credential_endpoint ?? (issuer.endsWith('/') ? `${issuer}credential` : `${issuer}/credential`));
|
|
81
|
-
if (metadata?.deferred_credential_endpoint) {
|
|
82
|
-
builder.withDeferredCredentialEndpoint(metadata.deferred_credential_endpoint);
|
|
83
|
-
}
|
|
84
|
-
const ids: string[] = (request.credential_offer as CredentialOfferPayloadV1_0_13).credential_configuration_ids;
|
|
85
|
-
// if there's only one in the offer, we pre-select it. if not, you should provide the credentialType
|
|
86
|
-
if (ids.length && ids.length === 1) {
|
|
87
|
-
builder.withCredentialIdentifier(ids[0]);
|
|
93
|
+
builder = CredentialRequestClientBuilderV1_0_11.fromCredentialOfferRequest(opts);
|
|
94
|
+
} else {
|
|
95
|
+
builder = CredentialRequestClientBuilderV1_0_13.fromCredentialOfferRequest(opts);
|
|
88
96
|
}
|
|
89
|
-
|
|
97
|
+
|
|
98
|
+
return new CredentialRequestClientBuilder(builder);
|
|
90
99
|
}
|
|
91
100
|
|
|
92
101
|
public static fromCredentialOffer({
|
|
@@ -96,78 +105,100 @@ export class CredentialRequestClientBuilder {
|
|
|
96
105
|
credentialOffer: CredentialOfferRequestWithBaseUrl;
|
|
97
106
|
metadata?: EndpointMetadata;
|
|
98
107
|
}): CredentialRequestClientBuilder {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
108
|
+
const version = determineSpecVersionFromOffer(credentialOffer.credential_offer);
|
|
109
|
+
let builder;
|
|
110
|
+
|
|
111
|
+
if (version < OpenId4VCIVersion.VER_1_0_13) {
|
|
112
|
+
builder = CredentialRequestClientBuilderV1_0_11.fromCredentialOffer({
|
|
113
|
+
credentialOffer,
|
|
114
|
+
metadata,
|
|
115
|
+
});
|
|
116
|
+
} else {
|
|
117
|
+
builder = CredentialRequestClientBuilderV1_0_13.fromCredentialOffer({
|
|
118
|
+
credentialOffer,
|
|
119
|
+
metadata,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return new CredentialRequestClientBuilder(builder);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public getVersion(): OpenId4VCIVersion | undefined {
|
|
127
|
+
return this._builder.version;
|
|
104
128
|
}
|
|
105
129
|
|
|
106
|
-
public withCredentialEndpointFromMetadata(metadata: CredentialIssuerMetadataV1_0_13): this {
|
|
107
|
-
this.
|
|
130
|
+
public withCredentialEndpointFromMetadata(metadata: CredentialIssuerMetadata | CredentialIssuerMetadataV1_0_13): this {
|
|
131
|
+
if (isV1_0_13(this._builder)) {
|
|
132
|
+
this._builder.withCredentialEndpointFromMetadata(metadata as CredentialIssuerMetadataV1_0_13);
|
|
133
|
+
} else {
|
|
134
|
+
this._builder.withCredentialEndpointFromMetadata(metadata as CredentialIssuerMetadata);
|
|
135
|
+
}
|
|
108
136
|
return this;
|
|
109
137
|
}
|
|
110
138
|
|
|
111
139
|
public withCredentialEndpoint(credentialEndpoint: string): this {
|
|
112
|
-
this.credentialEndpoint
|
|
140
|
+
this._builder.withCredentialEndpoint(credentialEndpoint);
|
|
113
141
|
return this;
|
|
114
142
|
}
|
|
115
143
|
|
|
116
|
-
public withDeferredCredentialEndpointFromMetadata(metadata: CredentialIssuerMetadataV1_0_13): this {
|
|
117
|
-
this.
|
|
144
|
+
public withDeferredCredentialEndpointFromMetadata(metadata: CredentialIssuerMetadata | CredentialIssuerMetadataV1_0_13): this {
|
|
145
|
+
if (isV1_0_13(this._builder)) {
|
|
146
|
+
this._builder.withDeferredCredentialEndpointFromMetadata(metadata as CredentialIssuerMetadataV1_0_13);
|
|
147
|
+
} else {
|
|
148
|
+
this._builder.withDeferredCredentialEndpointFromMetadata(metadata as CredentialIssuerMetadata);
|
|
149
|
+
}
|
|
118
150
|
return this;
|
|
119
151
|
}
|
|
120
152
|
|
|
121
153
|
public withDeferredCredentialEndpoint(deferredCredentialEndpoint: string): this {
|
|
122
|
-
this.deferredCredentialEndpoint
|
|
154
|
+
this._builder.withDeferredCredentialEndpoint(deferredCredentialEndpoint);
|
|
123
155
|
return this;
|
|
124
156
|
}
|
|
125
157
|
|
|
126
158
|
public withDeferredCredentialAwait(deferredCredentialAwait: boolean, deferredCredentialIntervalInMS?: number): this {
|
|
127
|
-
this.deferredCredentialAwait
|
|
128
|
-
this.deferredCredentialIntervalInMS = deferredCredentialIntervalInMS ?? 5000;
|
|
159
|
+
this._builder.withDeferredCredentialAwait(deferredCredentialAwait, deferredCredentialIntervalInMS);
|
|
129
160
|
return this;
|
|
130
161
|
}
|
|
131
162
|
|
|
132
163
|
public withCredentialIdentifier(credentialIdentifier: string): this {
|
|
133
|
-
this.
|
|
164
|
+
if (this._builder.version === undefined || this._builder.version < OpenId4VCIVersion.VER_1_0_13) {
|
|
165
|
+
throw new Error('Version of spec should be equal or higher than v1_0_13');
|
|
166
|
+
}
|
|
167
|
+
(this._builder as CredentialRequestClientBuilderV1_0_13).withCredentialIdentifier(credentialIdentifier);
|
|
134
168
|
return this;
|
|
135
169
|
}
|
|
136
170
|
|
|
137
171
|
public withCredentialType(credentialTypes: string | string[]): this {
|
|
138
|
-
this.
|
|
172
|
+
this._builder.withCredentialType(credentialTypes);
|
|
139
173
|
return this;
|
|
140
174
|
}
|
|
141
175
|
|
|
142
176
|
public withFormat(format: CredentialFormat | OID4VCICredentialFormat): this {
|
|
143
|
-
this.format
|
|
177
|
+
this._builder.withFormat(format);
|
|
144
178
|
return this;
|
|
145
179
|
}
|
|
146
180
|
|
|
147
181
|
public withSubjectIssuance(subjectIssuance: ExperimentalSubjectIssuance): this {
|
|
148
|
-
this.subjectIssuance
|
|
182
|
+
this._builder.withSubjectIssuance(subjectIssuance);
|
|
149
183
|
return this;
|
|
150
184
|
}
|
|
151
185
|
|
|
152
186
|
public withToken(accessToken: string): this {
|
|
153
|
-
this.
|
|
187
|
+
this._builder.withToken(accessToken);
|
|
154
188
|
return this;
|
|
155
189
|
}
|
|
156
190
|
|
|
157
191
|
public withTokenFromResponse(response: AccessTokenResponse): this {
|
|
158
|
-
this.
|
|
192
|
+
this._builder.withTokenFromResponse(response);
|
|
159
193
|
return this;
|
|
160
194
|
}
|
|
161
195
|
|
|
162
196
|
public withVersion(version: OpenId4VCIVersion): this {
|
|
163
|
-
this.version
|
|
197
|
+
this._builder.withVersion(version);
|
|
164
198
|
return this;
|
|
165
199
|
}
|
|
166
200
|
|
|
167
|
-
public build()
|
|
168
|
-
|
|
169
|
-
this.withVersion(OpenId4VCIVersion.VER_1_0_11);
|
|
170
|
-
}
|
|
171
|
-
return new CredentialRequestClient(this);
|
|
201
|
+
public build() {
|
|
202
|
+
return this._builder.build();
|
|
172
203
|
}
|
|
173
204
|
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AccessTokenResponse,
|
|
3
|
+
CredentialIssuerMetadataV1_0_13,
|
|
4
|
+
CredentialOfferPayloadV1_0_13,
|
|
5
|
+
CredentialOfferRequestWithBaseUrl,
|
|
6
|
+
determineSpecVersionFromOffer,
|
|
7
|
+
EndpointMetadata,
|
|
8
|
+
ExperimentalSubjectIssuance,
|
|
9
|
+
getIssuerFromCredentialOfferPayload,
|
|
10
|
+
OID4VCICredentialFormat,
|
|
11
|
+
OpenId4VCIVersion,
|
|
12
|
+
UniformCredentialOfferRequest,
|
|
13
|
+
} from '@sphereon/oid4vci-common';
|
|
14
|
+
import { CredentialFormat } from '@sphereon/ssi-types';
|
|
15
|
+
|
|
16
|
+
import { CredentialOfferClient } from './CredentialOfferClient';
|
|
17
|
+
import { CredentialRequestClient } from './CredentialRequestClient';
|
|
18
|
+
|
|
19
|
+
export class CredentialRequestClientBuilderV1_0_13 {
|
|
20
|
+
credentialEndpoint?: string;
|
|
21
|
+
deferredCredentialEndpoint?: string;
|
|
22
|
+
deferredCredentialAwait = false;
|
|
23
|
+
deferredCredentialIntervalInMS = 5000;
|
|
24
|
+
credentialIdentifier?: string;
|
|
25
|
+
credentialTypes?: string[] = [];
|
|
26
|
+
format?: CredentialFormat | OID4VCICredentialFormat;
|
|
27
|
+
token?: string;
|
|
28
|
+
version?: OpenId4VCIVersion;
|
|
29
|
+
subjectIssuance?: ExperimentalSubjectIssuance;
|
|
30
|
+
|
|
31
|
+
public static fromCredentialIssuer({
|
|
32
|
+
credentialIssuer,
|
|
33
|
+
metadata,
|
|
34
|
+
version,
|
|
35
|
+
credentialIdentifier,
|
|
36
|
+
credentialTypes,
|
|
37
|
+
}: {
|
|
38
|
+
credentialIssuer: string;
|
|
39
|
+
metadata?: EndpointMetadata;
|
|
40
|
+
version?: OpenId4VCIVersion;
|
|
41
|
+
credentialIdentifier?: string;
|
|
42
|
+
credentialTypes?: string | string[];
|
|
43
|
+
}): CredentialRequestClientBuilderV1_0_13 {
|
|
44
|
+
const issuer = credentialIssuer;
|
|
45
|
+
const builder = new CredentialRequestClientBuilderV1_0_13();
|
|
46
|
+
builder.withVersion(version ?? OpenId4VCIVersion.VER_1_0_13);
|
|
47
|
+
builder.withCredentialEndpoint(metadata?.credential_endpoint ?? (issuer.endsWith('/') ? `${issuer}credential` : `${issuer}/credential`));
|
|
48
|
+
if (metadata?.deferred_credential_endpoint) {
|
|
49
|
+
builder.withDeferredCredentialEndpoint(metadata.deferred_credential_endpoint);
|
|
50
|
+
}
|
|
51
|
+
if (credentialIdentifier) {
|
|
52
|
+
builder.withCredentialIdentifier(credentialIdentifier);
|
|
53
|
+
}
|
|
54
|
+
if (credentialTypes) {
|
|
55
|
+
builder.withCredentialType(credentialTypes);
|
|
56
|
+
}
|
|
57
|
+
return builder;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public static async fromURI({ uri, metadata }: { uri: string; metadata?: EndpointMetadata }): Promise<CredentialRequestClientBuilderV1_0_13> {
|
|
61
|
+
const offer = await CredentialOfferClient.fromURI(uri);
|
|
62
|
+
return CredentialRequestClientBuilderV1_0_13.fromCredentialOfferRequest({ request: offer, ...offer, metadata, version: offer.version });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public static fromCredentialOfferRequest(opts: {
|
|
66
|
+
request: UniformCredentialOfferRequest;
|
|
67
|
+
scheme?: string;
|
|
68
|
+
baseUrl?: string;
|
|
69
|
+
version?: OpenId4VCIVersion;
|
|
70
|
+
metadata?: EndpointMetadata;
|
|
71
|
+
}): CredentialRequestClientBuilderV1_0_13 {
|
|
72
|
+
const { request, metadata } = opts;
|
|
73
|
+
const version = opts.version ?? request.version ?? determineSpecVersionFromOffer(request.original_credential_offer);
|
|
74
|
+
if (version < OpenId4VCIVersion.VER_1_0_13) {
|
|
75
|
+
throw new Error('Versions below v1.0.13 (draft 13) are not supported.');
|
|
76
|
+
}
|
|
77
|
+
const builder = new CredentialRequestClientBuilderV1_0_13();
|
|
78
|
+
const issuer = getIssuerFromCredentialOfferPayload(request.credential_offer) ?? (metadata?.issuer as string);
|
|
79
|
+
builder.withVersion(version);
|
|
80
|
+
builder.withCredentialEndpoint(metadata?.credential_endpoint ?? (issuer.endsWith('/') ? `${issuer}credential` : `${issuer}/credential`));
|
|
81
|
+
if (metadata?.deferred_credential_endpoint) {
|
|
82
|
+
builder.withDeferredCredentialEndpoint(metadata.deferred_credential_endpoint);
|
|
83
|
+
}
|
|
84
|
+
const ids: string[] = (request.credential_offer as CredentialOfferPayloadV1_0_13).credential_configuration_ids;
|
|
85
|
+
// if there's only one in the offer, we pre-select it. if not, you should provide the credentialType
|
|
86
|
+
if (ids.length && ids.length === 1) {
|
|
87
|
+
builder.withCredentialIdentifier(ids[0]);
|
|
88
|
+
}
|
|
89
|
+
return builder;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public static fromCredentialOffer({
|
|
93
|
+
credentialOffer,
|
|
94
|
+
metadata,
|
|
95
|
+
}: {
|
|
96
|
+
credentialOffer: CredentialOfferRequestWithBaseUrl;
|
|
97
|
+
metadata?: EndpointMetadata;
|
|
98
|
+
}): CredentialRequestClientBuilderV1_0_13 {
|
|
99
|
+
return CredentialRequestClientBuilderV1_0_13.fromCredentialOfferRequest({
|
|
100
|
+
request: credentialOffer,
|
|
101
|
+
metadata,
|
|
102
|
+
version: credentialOffer.version,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public withCredentialEndpointFromMetadata(metadata: CredentialIssuerMetadataV1_0_13): this {
|
|
107
|
+
this.credentialEndpoint = metadata.credential_endpoint;
|
|
108
|
+
return this;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public withCredentialEndpoint(credentialEndpoint: string): this {
|
|
112
|
+
this.credentialEndpoint = credentialEndpoint;
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public withDeferredCredentialEndpointFromMetadata(metadata: CredentialIssuerMetadataV1_0_13): this {
|
|
117
|
+
this.deferredCredentialEndpoint = metadata.deferred_credential_endpoint;
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public withDeferredCredentialEndpoint(deferredCredentialEndpoint: string): this {
|
|
122
|
+
this.deferredCredentialEndpoint = deferredCredentialEndpoint;
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public withDeferredCredentialAwait(deferredCredentialAwait: boolean, deferredCredentialIntervalInMS?: number): this {
|
|
127
|
+
this.deferredCredentialAwait = deferredCredentialAwait;
|
|
128
|
+
this.deferredCredentialIntervalInMS = deferredCredentialIntervalInMS ?? 5000;
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
public withCredentialIdentifier(credentialIdentifier: string): this {
|
|
133
|
+
this.credentialIdentifier = credentialIdentifier;
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public withCredentialType(credentialTypes: string | string[]): this {
|
|
138
|
+
this.credentialTypes = Array.isArray(credentialTypes) ? credentialTypes : [credentialTypes];
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public withFormat(format: CredentialFormat | OID4VCICredentialFormat): this {
|
|
143
|
+
this.format = format;
|
|
144
|
+
return this;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public withSubjectIssuance(subjectIssuance: ExperimentalSubjectIssuance): this {
|
|
148
|
+
this.subjectIssuance = subjectIssuance;
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public withToken(accessToken: string): this {
|
|
153
|
+
this.token = accessToken;
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public withTokenFromResponse(response: AccessTokenResponse): this {
|
|
158
|
+
this.token = response.access_token;
|
|
159
|
+
return this;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
public withVersion(version: OpenId4VCIVersion): this {
|
|
163
|
+
this.version = version;
|
|
164
|
+
return this;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public build(): CredentialRequestClient {
|
|
168
|
+
if (!this.version) {
|
|
169
|
+
this.withVersion(OpenId4VCIVersion.VER_1_0_11);
|
|
170
|
+
}
|
|
171
|
+
return new CredentialRequestClient(this);
|
|
172
|
+
}
|
|
173
|
+
}
|
package/lib/OpenID4VCIClient.ts
CHANGED
|
@@ -41,7 +41,7 @@ import { createAuthorizationRequestUrl } from './AuthorizationCodeClient';
|
|
|
41
41
|
import { createAuthorizationRequestUrlV1_0_11 } from './AuthorizationCodeClientV1_0_11';
|
|
42
42
|
import { CredentialOfferClient } from './CredentialOfferClient';
|
|
43
43
|
import { CredentialRequestOpts } from './CredentialRequestClient';
|
|
44
|
-
import {
|
|
44
|
+
import { CredentialRequestClientBuilderV1_0_13 } from './CredentialRequestClientBuilderV1_0_13';
|
|
45
45
|
import { CredentialRequestClientBuilderV1_0_11 } from './CredentialRequestClientBuilderV1_0_11';
|
|
46
46
|
import { MetadataClient } from './MetadataClient';
|
|
47
47
|
import { OpenID4VCIClientStateV1_0_11 } from './OpenID4VCIClientV1_0_11';
|
|
@@ -273,6 +273,7 @@ export class OpenID4VCIClient {
|
|
|
273
273
|
authorizationResponse?: string | AuthorizationResponse; // Pass in an auth response, either as URI/redirect, or object
|
|
274
274
|
code?: string; // Directly pass in a code from an auth response
|
|
275
275
|
redirectUri?: string;
|
|
276
|
+
additionalRequestParams?: Record<string, any>;
|
|
276
277
|
}): Promise<AccessTokenResponse> {
|
|
277
278
|
const { pin, clientId } = opts ?? {};
|
|
278
279
|
let { redirectUri } = opts ?? {};
|
|
@@ -312,6 +313,7 @@ export class OpenID4VCIClient {
|
|
|
312
313
|
code,
|
|
313
314
|
redirectUri,
|
|
314
315
|
asOpts: { clientId: this.clientId },
|
|
316
|
+
...(opts?.additionalRequestParams && { additionalParams: opts.additionalRequestParams }),
|
|
315
317
|
});
|
|
316
318
|
|
|
317
319
|
if (response.errorBody) {
|
|
@@ -368,7 +370,7 @@ export class OpenID4VCIClient {
|
|
|
368
370
|
if (jwk) this._state.jwk = jwk;
|
|
369
371
|
if (kid) this._state.kid = kid;
|
|
370
372
|
|
|
371
|
-
let requestBuilder:
|
|
373
|
+
let requestBuilder: CredentialRequestClientBuilderV1_0_13 | CredentialRequestClientBuilderV1_0_11;
|
|
372
374
|
if (this.version() < OpenId4VCIVersion.VER_1_0_13) {
|
|
373
375
|
requestBuilder = this.credentialOffer
|
|
374
376
|
? CredentialRequestClientBuilderV1_0_11.fromCredentialOffer({
|
|
@@ -383,11 +385,11 @@ export class OpenID4VCIClient {
|
|
|
383
385
|
});
|
|
384
386
|
} else {
|
|
385
387
|
requestBuilder = this.credentialOffer
|
|
386
|
-
?
|
|
388
|
+
? CredentialRequestClientBuilderV1_0_13.fromCredentialOffer({
|
|
387
389
|
credentialOffer: this.credentialOffer,
|
|
388
390
|
metadata: this.endpointMetadata,
|
|
389
391
|
})
|
|
390
|
-
:
|
|
392
|
+
: CredentialRequestClientBuilderV1_0_13.fromCredentialIssuer({
|
|
391
393
|
credentialIssuer: this.getIssuer(),
|
|
392
394
|
credentialTypes,
|
|
393
395
|
metadata: this.endpointMetadata,
|
|
@@ -20,13 +20,8 @@ import * as jose from 'jose';
|
|
|
20
20
|
// @ts-ignore
|
|
21
21
|
import nock from 'nock';
|
|
22
22
|
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
CredentialRequestClientBuilder,
|
|
26
|
-
CredentialRequestClientBuilderV1_0_11,
|
|
27
|
-
MetadataClientV1_0_11,
|
|
28
|
-
ProofOfPossessionBuilder,
|
|
29
|
-
} from '..';
|
|
23
|
+
import { CredentialOfferClient, MetadataClient, ProofOfPossessionBuilder } from '..';
|
|
24
|
+
import { CredentialRequestClientBuilder } from '../CredentialRequestClientBuilder';
|
|
30
25
|
|
|
31
26
|
import { IDENTIPROOF_ISSUER_URL, IDENTIPROOF_OID4VCI_METADATA, INITIATION_TEST, WALT_OID4VCI_METADATA } from './MetadataMocks';
|
|
32
27
|
import { getMockData } from './data/VciDataFixtures';
|
|
@@ -154,14 +149,14 @@ describe('Credential Request Client with Walt.id ', () => {
|
|
|
154
149
|
nock.cleanAll();
|
|
155
150
|
const WALT_IRR_URI =
|
|
156
151
|
'openid-initiate-issuance://?issuer=https%3A%2F%2Fjff.walt.id%2Fissuer-api%2Foidc%2F&credential_type=OpenBadgeCredential&pre-authorized_code=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhOTUyZjUxNi1jYWVmLTQ4YjMtODIxYy00OTRkYzgyNjljZjAiLCJwcmUtYXV0aG9yaXplZCI6dHJ1ZX0.YE5DlalcLC2ChGEg47CQDaN1gTxbaQqSclIVqsSAUHE&user_pin_required=false';
|
|
157
|
-
const credentialOffer = await
|
|
152
|
+
const credentialOffer = await CredentialOfferClient.fromURI(WALT_IRR_URI);
|
|
158
153
|
|
|
159
154
|
const request = credentialOffer.credential_offer;
|
|
160
|
-
const metadata = await
|
|
155
|
+
const metadata = await MetadataClient.retrieveAllMetadata(getIssuerFromCredentialOfferPayload(request) as string);
|
|
161
156
|
expect(metadata.credential_endpoint).toEqual(WALT_OID4VCI_METADATA.credential_endpoint);
|
|
162
157
|
expect(metadata.token_endpoint).toEqual(WALT_OID4VCI_METADATA.token_endpoint);
|
|
163
158
|
|
|
164
|
-
const credReqClient =
|
|
159
|
+
const credReqClient = CredentialRequestClientBuilder.fromCredentialOffer({
|
|
165
160
|
credentialOffer,
|
|
166
161
|
metadata,
|
|
167
162
|
}).build();
|
|
@@ -205,7 +200,7 @@ describe('Credential Request Client with different issuers ', () => {
|
|
|
205
200
|
const IRR_URI =
|
|
206
201
|
'openid-initiate-issuance://?issuer=https%3A%2F%2Fjff.walt.id%2Fissuer-api%2Fdefault%2Foidc%2F&credential_type=OpenBadgeCredential&pre-authorized_code=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIwMTc4OTNjYy04ZTY3LTQxNzItYWZlOS1lODcyYmYxNDBlNWMiLCJwcmUtYXV0aG9yaXplZCI6dHJ1ZX0.ODfq2AIhOcB61dAb3zMrXBJjPJaf53zkeHh_AssYyYA&user_pin_required=false';
|
|
207
202
|
const credentialOffer = await (
|
|
208
|
-
await
|
|
203
|
+
await CredentialRequestClientBuilder.fromURI({
|
|
209
204
|
uri: IRR_URI,
|
|
210
205
|
metadata: getMockData('walt')?.metadata as unknown as EndpointMetadata,
|
|
211
206
|
})
|
|
@@ -250,7 +245,7 @@ describe('Credential Request Client with different issuers ', () => {
|
|
|
250
245
|
const IRR_URI =
|
|
251
246
|
'openid-initiate-issuance://?issuer=https://launchpad.mattrlabs.com&credential_type=OpenBadgeCredential&pre-authorized_code=g0UCOj6RAN5AwHU6gczm_GzB4_lH6GW39Z0Dl2DOOiO';
|
|
252
247
|
const credentialOffer = await (
|
|
253
|
-
await
|
|
248
|
+
await CredentialRequestClientBuilder.fromURI({
|
|
254
249
|
uri: IRR_URI,
|
|
255
250
|
metadata: getMockData('mattr')?.metadata as unknown as EndpointMetadata,
|
|
256
251
|
})
|
|
@@ -273,7 +268,7 @@ describe('Credential Request Client with different issuers ', () => {
|
|
|
273
268
|
const IRR_URI =
|
|
274
269
|
'openid-initiate-issuance://?issuer=https://oidc4vc.diwala.io&credential_type=OpenBadgeCredential&pre-authorized_code=eyJhbGciOiJIUzI1NiJ9.eyJjcmVkZW50aWFsX3R5cGUiOiJPcGVuQmFkZ2VDcmVkZW50aWFsIiwiZXhwIjoxNjgxOTg0NDY3fQ.fEAHKz2nuWfiYHw406iNxr-81pWkNkbi31bWsYSf6Ng';
|
|
275
270
|
const credentialOffer = await (
|
|
276
|
-
await
|
|
271
|
+
await CredentialRequestClientBuilder.fromURI({
|
|
277
272
|
uri: IRR_URI,
|
|
278
273
|
metadata: getMockData('diwala')?.metadata as unknown as EndpointMetadata,
|
|
279
274
|
})
|
|
@@ -11,11 +11,13 @@ import {
|
|
|
11
11
|
} from '@sphereon/oid4vci-common';
|
|
12
12
|
import * as jose from 'jose';
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { CredentialRequestOpts, ProofOfPossessionBuilder } from '..';
|
|
15
|
+
import { CredentialRequestClientBuilder } from '../CredentialRequestClientBuilder';
|
|
15
16
|
|
|
16
17
|
import { IDENTIPROOF_ISSUER_URL, IDENTIPROOF_OID4VCI_METADATA, INITIATION_TEST_URI, WALT_ISSUER_URL, WALT_OID4VCI_METADATA } from './MetadataMocks';
|
|
17
18
|
|
|
18
19
|
const partialJWT = 'eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmN';
|
|
20
|
+
const partialJWT_withoutDid = 'eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJlYmZlYjFmNzEyZWJjNmYxYzI3N';
|
|
19
21
|
|
|
20
22
|
/*const jwtv1_0_08: Jwt = {
|
|
21
23
|
header: { alg: Alg.ES256, kid: 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: 'jwt' },
|
|
@@ -27,8 +29,15 @@ const jwtv1_0_11: Jwt = {
|
|
|
27
29
|
payload: { iss: 'sphereon:wallet', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: IDENTIPROOF_ISSUER_URL },
|
|
28
30
|
};
|
|
29
31
|
|
|
32
|
+
const jwtv1_0_13_withoutDid: Jwt = {
|
|
33
|
+
header: { alg: Alg.ES256, kid: 'ebfeb1f712ebc6f1c276e12ec21/keys/1', typ: 'openid4vci-proof+jwt' },
|
|
34
|
+
payload: { iss: 'sphereon:wallet', nonce: 'tZignsnFbp', jti: 'tZignsnFbp223', aud: IDENTIPROOF_ISSUER_URL },
|
|
35
|
+
};
|
|
36
|
+
|
|
30
37
|
const kid = 'did:example:ebfeb1f712ebc6f1c276e12ec21/keys/1';
|
|
31
38
|
|
|
39
|
+
const kid_withoutDid = 'ebfeb1f712ebc6f1c276e12ec21/keys/1';
|
|
40
|
+
|
|
32
41
|
let keypair: KeyPair;
|
|
33
42
|
|
|
34
43
|
beforeAll(async () => {
|
|
@@ -81,7 +90,7 @@ describe('Credential Request Client Builder', () => {
|
|
|
81
90
|
.build();
|
|
82
91
|
expect(credReqClient.credentialRequestOpts.credentialEndpoint).toBe('https://oidc4vci.demo.spruceid.com/credential');
|
|
83
92
|
expect(credReqClient.credentialRequestOpts.format).toBe('jwt_vc');
|
|
84
|
-
expect(credReqClient.credentialRequestOpts.credentialIdentifier).toStrictEqual('credentialType');
|
|
93
|
+
expect((credReqClient.credentialRequestOpts as CredentialRequestOpts).credentialIdentifier).toStrictEqual('credentialType');
|
|
85
94
|
expect(credReqClient.credentialRequestOpts.token).toBe('token');
|
|
86
95
|
});
|
|
87
96
|
|
|
@@ -115,6 +124,35 @@ describe('Credential Request Client Builder', () => {
|
|
|
115
124
|
}
|
|
116
125
|
});
|
|
117
126
|
|
|
127
|
+
it('should build credential request correctly without did', async () => {
|
|
128
|
+
const credReqClient = (await CredentialRequestClientBuilder.fromURI({ uri: INITIATION_TEST_URI }))
|
|
129
|
+
.withCredentialEndpoint('https://oidc4vci.demo.spruceid.com/credential')
|
|
130
|
+
.withFormat('jwt_vc')
|
|
131
|
+
.withCredentialType('OpenBadgeCredential')
|
|
132
|
+
.build();
|
|
133
|
+
const proof: ProofOfPossession = await ProofOfPossessionBuilder.fromJwt({
|
|
134
|
+
jwt: jwtv1_0_13_withoutDid,
|
|
135
|
+
callbacks: {
|
|
136
|
+
signCallback: proofOfPossessionCallbackFunction,
|
|
137
|
+
verifyCallback: proofOfPossessionVerifierCallbackFunction,
|
|
138
|
+
},
|
|
139
|
+
version: OpenId4VCIVersion.VER_1_0_13,
|
|
140
|
+
})
|
|
141
|
+
.withClientId('sphereon:wallet')
|
|
142
|
+
.withKid(kid_withoutDid)
|
|
143
|
+
.build();
|
|
144
|
+
await proofOfPossessionVerifierCallbackFunction({ ...proof, kid: kid_withoutDid });
|
|
145
|
+
const credentialRequest: CredentialRequestV1_0_13 = await credReqClient.createCredentialRequest({
|
|
146
|
+
proofInput: proof,
|
|
147
|
+
credentialTypes: 'OpenBadgeCredential',
|
|
148
|
+
version: OpenId4VCIVersion.VER_1_0_13,
|
|
149
|
+
});
|
|
150
|
+
expect(credentialRequest.proof?.jwt).toContain(partialJWT_withoutDid);
|
|
151
|
+
if ('types' in credentialRequest) {
|
|
152
|
+
expect(credentialRequest.types).toStrictEqual(['OpenBadgeCredential']);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
118
156
|
it('should build correctly from metadata', async () => {
|
|
119
157
|
const credReqClient = (
|
|
120
158
|
await CredentialRequestClientBuilder.fromURI({
|