@pagopa/io-wallet-oauth2 0.4.2 → 0.5.0

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/README.md ADDED
@@ -0,0 +1,293 @@
1
+ ## @pagopa/io-wallet-oauth2
2
+
3
+ This package provides functionalities to manage the **OAuth 2.0** part of the **OpenID for Verifiable Credentials Issuance (OID4VCI)** and **OpenID for Verifiable Presentations (OIDVP)** protocol flows, specifically tailored for the Italian Wallet ecosystem.
4
+
5
+ ## Installation
6
+
7
+ To install the package, use your preferred package manager:
8
+
9
+ ```bash
10
+ # Using pnpm
11
+ pnpm add @pagopa/io-wallet-oauth2
12
+
13
+ # Using yarn
14
+ yarn add @pagopa/io-wallet-oauth2
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### `createTokenDPoP`
20
+
21
+ ```typescript
22
+ import { JwtSignerJwk, createTokenDPoP, CreateTokenDPoPOptions, HttpMethod } from "@pagopa/io-wallet-oauth2"
23
+
24
+ const signer: JwtSignerJwk = {
25
+ method: 'jwk',
26
+ publicJwk: {/* JWK description here */},
27
+ alg: 'ES256'
28
+ }
29
+
30
+ /**
31
+ * Scenario 1: Basic DPoP for token request
32
+ */
33
+
34
+ const callbacks = {
35
+ signJwt: (signer: JwtSignerJwk, {header, payload}) => {/* Perform JWT signing */},
36
+ hash: (data: Uint8Array, algorithm: HashAlgorithm) => {/* Perform hash operation */},
37
+ generateRandom: (byteLength: number) => {/* Generate an Uint8Array containing a sequence of byteLength random bytes */}
38
+ }
39
+
40
+ const options: CreateTokenDPoPOptions = {
41
+ callbacks,
42
+ signer,
43
+ tokenRequest: {
44
+ method: HttpMethod.Post,
45
+ url: 'https://example.com/token'
46
+ }
47
+ }
48
+
49
+ const jwt = await createTokenDPoP(options)
50
+
51
+ /**
52
+ * End Scenario 1
53
+ */
54
+
55
+ /**
56
+ * Scenario 2: DPoP bound to an access token
57
+ */
58
+
59
+ const callbacks = {
60
+ signJwt: (signer: JwtSignerJwk, {header, payload}) => {/* Perform JWT signing */},
61
+ hash: (data: Uint8Array, algorithm: HashAlgorithm) => {/* Perform hash operation */},
62
+ generateRandom: (byteLength: number) => {/* Generate random bytes */}
63
+ }
64
+
65
+ const options: CreateTokenDPoPOptions = {
66
+ callbacks,
67
+ signer,
68
+ tokenRequest: {
69
+ method: HttpMethod.Post,
70
+ url: 'https://example.com/resource'
71
+ },
72
+ accessToken: 'your_access_token_here'
73
+ }
74
+
75
+ const jwt = await createTokenDPoP(options)
76
+
77
+ /**
78
+ * End Scenario 2
79
+ */
80
+
81
+ ```
82
+
83
+
84
+
85
+ ### `fetchTokenResponse`
86
+
87
+ ```typescript
88
+ import { fetchTokenResponse, FetchTokenResponseOptions, AccessTokenResponse } from "@pagopa/io-wallet-oauth2"
89
+
90
+ const callbacks = {
91
+ fetch: (url, options) => {/* Implement fetch logic */}
92
+ ...
93
+ }
94
+ const accessTokenRequest = createTokenRequest({
95
+ authorizationCode: "authorization_code_here",
96
+ pkceCodeVerifier: "code_verifier_here",
97
+ callbacks,
98
+ redirect_uri: "https://client.example.com/callback"
99
+ });
100
+ const options: FetchTokenResponseOptions = {
101
+ accessTokenEndpoint: "https://authorization-server.example.com/token",
102
+ accessTokenRequest,
103
+ callbacks,
104
+ clientAttestationDPoP: "eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3Arand0In0...",
105
+ walletAttestation: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9..."
106
+ }
107
+
108
+ const tokenResponse: AccessTokenResponse = await fetchTokenResponse(options)
109
+ ```
110
+
111
+ ## API Reference
112
+
113
+ ### `createTokenDPoP`
114
+
115
+ ```typescript
116
+ /**
117
+ * Options for Token Request DPoP generation
118
+ */
119
+ export interface CreateTokenDPoPOptions {
120
+ /**
121
+ * The access token to which the dpop jwt should be bound. Required
122
+ * when the dpop will be sent along with an access token.
123
+ *
124
+ * If provided, the `hash` callback parameter also needs to be provided
125
+ */
126
+ accessToken?: string;
127
+
128
+ /**
129
+ * Object containing callbacks for DPoP generation and signature
130
+ */
131
+ callbacks: Partial<Pick<CallbackContext, "generateRandom">> &
132
+ Pick<CallbackContext, "hash" | "signJwt">;
133
+
134
+ /**
135
+ * Creation time of the JWT. If not provided the current date will be used
136
+ */
137
+ issuedAt?: Date;
138
+
139
+ /**
140
+ * jti claim for the DPoP JWT. If not provided, a random one will be generated
141
+ * if a generateRandom callback is provided
142
+ */
143
+ jti?: string;
144
+
145
+ /**
146
+ * The signer of the dpop jwt. Only jwk signer allowed.
147
+ */
148
+ signer: JwtSignerJwk;
149
+
150
+ /**
151
+ * The request for which to create the dpop jwt
152
+ */
153
+ tokenRequest: {
154
+ method: HttpMethod;
155
+ url: string;
156
+ };
157
+ }
158
+
159
+ /**
160
+ * Creates a signed Token DPoP with the given cryptographic material and data.
161
+ * It is used to create DPoP proofs for token requests and credential requests.
162
+ * @param options {@link CreateTokenDPoPOptions}
163
+ * @returns A Promise that resolves with the signed DPoP JWT string
164
+ * @throws {@link CreateTokenDPoPError} in case neither a default jti nor a generateRandom
165
+ * callback have been provided or the signJwt callback throws
166
+ */
167
+ async function createTokenDPoP(options: CreateTokenDPoPOptions): Promise<string>
168
+ ```
169
+
170
+
171
+ ### `fetchTokenResponse`
172
+
173
+ ```typescript
174
+ /**
175
+ * Options for fetching an access token response
176
+ */
177
+ export interface FetchTokenResponseOptions {
178
+ /**
179
+ * The endpoint URL where the access token request will be sent
180
+ * This should be the authorization server's token endpoint
181
+ */
182
+ accessTokenEndpoint: string;
183
+
184
+ /**
185
+ * The access token request payload
186
+ */
187
+ accessTokenRequest: AccessTokenRequest;
188
+
189
+ /**
190
+ * Callbacks to use for requesting access token
191
+ */
192
+ callbacks: Pick<CallbackContext, "fetch">;
193
+
194
+ /**
195
+ * The client attestation Demonstration of Proof-of-Possession (DPoP) token
196
+ * Used for OAuth-Client-Attestation-PoP header to prove possession of the client key
197
+ */
198
+ clientAttestationDPoP: string;
199
+
200
+ /**
201
+ * The wallet attestation JWT that proves the client's identity and capabilities
202
+ * Used for OAuth-Client-Attestation header
203
+ */
204
+ walletAttestation: string;
205
+ }
206
+
207
+ /**
208
+ * Access token request payload
209
+ */
210
+ export type AccessTokenRequest = {
211
+ grant_type: "authorization_code" | "refresh_token";
212
+ code?: string;
213
+ code_verifier?: string;
214
+ redirect_uri?: string;
215
+ refresh_token?: string;
216
+ [key: string]: unknown;
217
+ }
218
+
219
+ /**
220
+ * Access token response
221
+ */
222
+ export type AccessTokenResponse = {
223
+ access_token: string;
224
+ token_type: "DPoP";
225
+ expires_in?: number;
226
+ refresh_token?: string;
227
+ authorization_details?: Array<{
228
+ type: "openid_credential";
229
+ credential_configuration_id?: string;
230
+ credential_identifiers?: string[];
231
+ [key: string]: unknown;
232
+ }>;
233
+ [key: string]: unknown;
234
+ }
235
+
236
+ /**
237
+ * Sends an access token request to the authorization server and returns the response
238
+ * @param options {@link FetchTokenResponseOptions}
239
+ * @returns A Promise that resolves with the parsed access token response
240
+ * @throws {@link UnexpectedStatusCodeError} When the server returns a non-200 status code
241
+ * @throws {@link ValidationError} When the response cannot be parsed as a valid access token response
242
+ * @throws {@link FetchTokenResponseError} When an unexpected error occurs during the request
243
+ */
244
+ async function fetchTokenResponse(options: FetchTokenResponseOptions): Promise<AccessTokenResponse>
245
+ ```
246
+
247
+ ### Errors
248
+
249
+ ```typescript
250
+ export class Oauth2Error extends Error {
251
+ constructor(
252
+ message: string,
253
+ public readonly statusCode?: number,
254
+ ) {
255
+ super(message);
256
+ this.name = "Oauth2Error";
257
+ }
258
+ }
259
+ ```
260
+ Generic error thrown on OAuth2 operations
261
+
262
+ ```typescript
263
+ export class PushedAuthorizationRequestError extends Oauth2Error {
264
+ constructor(
265
+ message: string,
266
+ public readonly statusCode?: number,
267
+ ) {
268
+ super(message);
269
+ this.name = "PushedAuthorizationRequestError";
270
+ }
271
+ }
272
+ ```
273
+ Custom error thrown when pushed authorization request operations fail
274
+
275
+ ```typescript
276
+ export class CreateTokenDPoPError extends Oauth2Error {
277
+ constructor(message: string) {
278
+ super(message);
279
+ this.name = "CreateTokenDPoPError";
280
+ }
281
+ }
282
+ ```
283
+ Error thrown in case `createTokenDPoP` is called without neither a custom jti nor a generateRandom callback or when the signJwt callback throws
284
+
285
+ ```typescript
286
+ export class FetchTokenResponseError extends Oauth2Error {
287
+ constructor(message: string) {
288
+ super(message);
289
+ this.name = "FetchTokenResponseError";
290
+ }
291
+ }
292
+ ```
293
+ Error thrown when an unexpected error occurs during the access token request