@tdacorp/identity-client 0.2.3 → 0.2.5
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/{chunk-MB66JUMG.js → chunk-36WOXP7V.js} +48 -15
- package/dist/index.cjs +48 -15
- package/dist/index.js +1 -1
- package/dist/next.cjs +47 -14
- package/dist/next.js +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/discovery.ts
|
|
2
2
|
import { createRemoteJWKSet } from "jose";
|
|
3
3
|
var DISCOVERY_CACHE_TTL_MS = 6e5;
|
|
4
|
+
var FETCH_TIMEOUT_MS = 2500;
|
|
4
5
|
var CACHE_MAX_ENTRIES = 100;
|
|
5
6
|
var discoveryCache = /* @__PURE__ */ new Map();
|
|
6
7
|
var discoveryPending = /* @__PURE__ */ new Map();
|
|
@@ -31,23 +32,36 @@ function assertHttps(url, label) {
|
|
|
31
32
|
throw new Error(`Discovery: ${label} "${url}" must be https (loopback hosts are the only http exception)`);
|
|
32
33
|
}
|
|
33
34
|
}
|
|
35
|
+
var ENDPOINT_FIELDS = [
|
|
36
|
+
{ field: "jwks_uri", required: true },
|
|
37
|
+
{ field: "token_endpoint", required: true },
|
|
38
|
+
{ field: "authorization_endpoint", required: true },
|
|
39
|
+
{ field: "userinfo_endpoint", required: false },
|
|
40
|
+
{ field: "end_session_endpoint", required: false },
|
|
41
|
+
{ field: "revocation_endpoint", required: false },
|
|
42
|
+
{ field: "introspection_endpoint", required: false },
|
|
43
|
+
{ field: "registration_endpoint", required: false }
|
|
44
|
+
];
|
|
45
|
+
function validateEndpointField(field, url, issuerOrigin) {
|
|
46
|
+
assertHttps(url, field);
|
|
47
|
+
if (new URL(url).origin !== issuerOrigin) {
|
|
48
|
+
throw new Error(`Discovery: ${field} "${url}" is not same-origin as issuer`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
34
51
|
function validateDiscoveryDocument(document, issuerUrl) {
|
|
35
52
|
assertHttps(issuerUrl, "issuer");
|
|
36
|
-
assertHttps(document.jwks_uri, "jwks_uri");
|
|
37
|
-
assertHttps(document.token_endpoint, "token_endpoint");
|
|
38
|
-
assertHttps(document.authorization_endpoint, "authorization_endpoint");
|
|
39
53
|
if (document.issuer !== issuerUrl) {
|
|
40
54
|
throw new Error(`Discovery: document issuer "${document.issuer}" does not match the configured issuer "${issuerUrl}"`);
|
|
41
55
|
}
|
|
42
56
|
const issuerOrigin = new URL(issuerUrl).origin;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
57
|
+
for (const { field, required } of ENDPOINT_FIELDS) {
|
|
58
|
+
const value = document[field];
|
|
59
|
+
if (value === void 0 && !required) continue;
|
|
60
|
+
if (typeof value !== "string") {
|
|
61
|
+
const requirement = required ? "is required and must be a string" : ", if present, must be a string";
|
|
62
|
+
throw new Error(`Discovery: ${field} ${requirement}`);
|
|
63
|
+
}
|
|
64
|
+
validateEndpointField(field, value, issuerOrigin);
|
|
51
65
|
}
|
|
52
66
|
}
|
|
53
67
|
async function fetchDiscovery(issuerUrl) {
|
|
@@ -58,7 +72,10 @@ async function fetchDiscovery(issuerUrl) {
|
|
|
58
72
|
}
|
|
59
73
|
const pending = discoveryPending.get(issuerUrl);
|
|
60
74
|
if (pending) return pending;
|
|
61
|
-
const promise = fetch(discoveryUrl(issuerUrl), {
|
|
75
|
+
const promise = fetch(discoveryUrl(issuerUrl), {
|
|
76
|
+
headers: { Accept: "application/json" },
|
|
77
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
78
|
+
}).then(
|
|
62
79
|
async (response) => {
|
|
63
80
|
if (!response.ok) {
|
|
64
81
|
throw new Error(`Discovery fetch for ${issuerUrl} failed: HTTP ${response.status}`);
|
|
@@ -115,6 +132,7 @@ function generateState() {
|
|
|
115
132
|
}
|
|
116
133
|
|
|
117
134
|
// src/token.ts
|
|
135
|
+
var FETCH_TIMEOUT_MS2 = 2500;
|
|
118
136
|
var TokenRequestError = class extends Error {
|
|
119
137
|
status;
|
|
120
138
|
error;
|
|
@@ -163,14 +181,29 @@ async function postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAut
|
|
|
163
181
|
} else {
|
|
164
182
|
body.set("client_id", clientId);
|
|
165
183
|
}
|
|
166
|
-
return fetch(tokenEndpoint, {
|
|
184
|
+
return fetch(tokenEndpoint, {
|
|
185
|
+
method: "POST",
|
|
186
|
+
headers,
|
|
187
|
+
body: body.toString(),
|
|
188
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
async function postTokenRequestOrThrow(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params) {
|
|
192
|
+
try {
|
|
193
|
+
return await postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
throw new TokenRequestError({
|
|
196
|
+
error: "network_failure",
|
|
197
|
+
errorDescription: error instanceof Error ? error.message : "Failed to reach the token endpoint"
|
|
198
|
+
});
|
|
199
|
+
}
|
|
167
200
|
}
|
|
168
201
|
async function readTokenResponseBody(response) {
|
|
169
202
|
return await response.json().catch(() => null);
|
|
170
203
|
}
|
|
171
204
|
async function exchangeAuthorizationCode(options) {
|
|
172
205
|
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
173
|
-
const response = await
|
|
206
|
+
const response = await postTokenRequestOrThrow(
|
|
174
207
|
discovery.token_endpoint,
|
|
175
208
|
options.clientId,
|
|
176
209
|
options.clientSecret,
|
|
@@ -190,7 +223,7 @@ async function exchangeAuthorizationCode(options) {
|
|
|
190
223
|
}
|
|
191
224
|
async function clientCredentialsGrant(options) {
|
|
192
225
|
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
193
|
-
const response = await
|
|
226
|
+
const response = await postTokenRequestOrThrow(
|
|
194
227
|
discovery.token_endpoint,
|
|
195
228
|
options.clientId,
|
|
196
229
|
options.clientSecret,
|
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
38
38
|
// src/discovery.ts
|
|
39
39
|
var import_jose = require("jose");
|
|
40
40
|
var DISCOVERY_CACHE_TTL_MS = 6e5;
|
|
41
|
+
var FETCH_TIMEOUT_MS = 2500;
|
|
41
42
|
var CACHE_MAX_ENTRIES = 100;
|
|
42
43
|
var discoveryCache = /* @__PURE__ */ new Map();
|
|
43
44
|
var discoveryPending = /* @__PURE__ */ new Map();
|
|
@@ -68,23 +69,36 @@ function assertHttps(url, label) {
|
|
|
68
69
|
throw new Error(`Discovery: ${label} "${url}" must be https (loopback hosts are the only http exception)`);
|
|
69
70
|
}
|
|
70
71
|
}
|
|
72
|
+
var ENDPOINT_FIELDS = [
|
|
73
|
+
{ field: "jwks_uri", required: true },
|
|
74
|
+
{ field: "token_endpoint", required: true },
|
|
75
|
+
{ field: "authorization_endpoint", required: true },
|
|
76
|
+
{ field: "userinfo_endpoint", required: false },
|
|
77
|
+
{ field: "end_session_endpoint", required: false },
|
|
78
|
+
{ field: "revocation_endpoint", required: false },
|
|
79
|
+
{ field: "introspection_endpoint", required: false },
|
|
80
|
+
{ field: "registration_endpoint", required: false }
|
|
81
|
+
];
|
|
82
|
+
function validateEndpointField(field, url, issuerOrigin) {
|
|
83
|
+
assertHttps(url, field);
|
|
84
|
+
if (new URL(url).origin !== issuerOrigin) {
|
|
85
|
+
throw new Error(`Discovery: ${field} "${url}" is not same-origin as issuer`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
71
88
|
function validateDiscoveryDocument(document, issuerUrl) {
|
|
72
89
|
assertHttps(issuerUrl, "issuer");
|
|
73
|
-
assertHttps(document.jwks_uri, "jwks_uri");
|
|
74
|
-
assertHttps(document.token_endpoint, "token_endpoint");
|
|
75
|
-
assertHttps(document.authorization_endpoint, "authorization_endpoint");
|
|
76
90
|
if (document.issuer !== issuerUrl) {
|
|
77
91
|
throw new Error(`Discovery: document issuer "${document.issuer}" does not match the configured issuer "${issuerUrl}"`);
|
|
78
92
|
}
|
|
79
93
|
const issuerOrigin = new URL(issuerUrl).origin;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
94
|
+
for (const { field, required } of ENDPOINT_FIELDS) {
|
|
95
|
+
const value = document[field];
|
|
96
|
+
if (value === void 0 && !required) continue;
|
|
97
|
+
if (typeof value !== "string") {
|
|
98
|
+
const requirement = required ? "is required and must be a string" : ", if present, must be a string";
|
|
99
|
+
throw new Error(`Discovery: ${field} ${requirement}`);
|
|
100
|
+
}
|
|
101
|
+
validateEndpointField(field, value, issuerOrigin);
|
|
88
102
|
}
|
|
89
103
|
}
|
|
90
104
|
async function fetchDiscovery(issuerUrl) {
|
|
@@ -95,7 +109,10 @@ async function fetchDiscovery(issuerUrl) {
|
|
|
95
109
|
}
|
|
96
110
|
const pending = discoveryPending.get(issuerUrl);
|
|
97
111
|
if (pending) return pending;
|
|
98
|
-
const promise = fetch(discoveryUrl(issuerUrl), {
|
|
112
|
+
const promise = fetch(discoveryUrl(issuerUrl), {
|
|
113
|
+
headers: { Accept: "application/json" },
|
|
114
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
115
|
+
}).then(
|
|
99
116
|
async (response) => {
|
|
100
117
|
if (!response.ok) {
|
|
101
118
|
throw new Error(`Discovery fetch for ${issuerUrl} failed: HTTP ${response.status}`);
|
|
@@ -152,6 +169,7 @@ function generateState() {
|
|
|
152
169
|
}
|
|
153
170
|
|
|
154
171
|
// src/token.ts
|
|
172
|
+
var FETCH_TIMEOUT_MS2 = 2500;
|
|
155
173
|
var TokenRequestError = class extends Error {
|
|
156
174
|
status;
|
|
157
175
|
error;
|
|
@@ -200,14 +218,29 @@ async function postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAut
|
|
|
200
218
|
} else {
|
|
201
219
|
body.set("client_id", clientId);
|
|
202
220
|
}
|
|
203
|
-
return fetch(tokenEndpoint, {
|
|
221
|
+
return fetch(tokenEndpoint, {
|
|
222
|
+
method: "POST",
|
|
223
|
+
headers,
|
|
224
|
+
body: body.toString(),
|
|
225
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
async function postTokenRequestOrThrow(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params) {
|
|
229
|
+
try {
|
|
230
|
+
return await postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params);
|
|
231
|
+
} catch (error) {
|
|
232
|
+
throw new TokenRequestError({
|
|
233
|
+
error: "network_failure",
|
|
234
|
+
errorDescription: error instanceof Error ? error.message : "Failed to reach the token endpoint"
|
|
235
|
+
});
|
|
236
|
+
}
|
|
204
237
|
}
|
|
205
238
|
async function readTokenResponseBody(response) {
|
|
206
239
|
return await response.json().catch(() => null);
|
|
207
240
|
}
|
|
208
241
|
async function exchangeAuthorizationCode(options) {
|
|
209
242
|
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
210
|
-
const response = await
|
|
243
|
+
const response = await postTokenRequestOrThrow(
|
|
211
244
|
discovery.token_endpoint,
|
|
212
245
|
options.clientId,
|
|
213
246
|
options.clientSecret,
|
|
@@ -227,7 +260,7 @@ async function exchangeAuthorizationCode(options) {
|
|
|
227
260
|
}
|
|
228
261
|
async function clientCredentialsGrant(options) {
|
|
229
262
|
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
230
|
-
const response = await
|
|
263
|
+
const response = await postTokenRequestOrThrow(
|
|
231
264
|
discovery.token_endpoint,
|
|
232
265
|
options.clientId,
|
|
233
266
|
options.clientSecret,
|
package/dist/index.js
CHANGED
package/dist/next.cjs
CHANGED
|
@@ -29,6 +29,7 @@ var import_server = require("next/server");
|
|
|
29
29
|
// src/discovery.ts
|
|
30
30
|
var import_jose = require("jose");
|
|
31
31
|
var DISCOVERY_CACHE_TTL_MS = 6e5;
|
|
32
|
+
var FETCH_TIMEOUT_MS = 2500;
|
|
32
33
|
var CACHE_MAX_ENTRIES = 100;
|
|
33
34
|
var discoveryCache = /* @__PURE__ */ new Map();
|
|
34
35
|
var discoveryPending = /* @__PURE__ */ new Map();
|
|
@@ -59,23 +60,36 @@ function assertHttps(url, label) {
|
|
|
59
60
|
throw new Error(`Discovery: ${label} "${url}" must be https (loopback hosts are the only http exception)`);
|
|
60
61
|
}
|
|
61
62
|
}
|
|
63
|
+
var ENDPOINT_FIELDS = [
|
|
64
|
+
{ field: "jwks_uri", required: true },
|
|
65
|
+
{ field: "token_endpoint", required: true },
|
|
66
|
+
{ field: "authorization_endpoint", required: true },
|
|
67
|
+
{ field: "userinfo_endpoint", required: false },
|
|
68
|
+
{ field: "end_session_endpoint", required: false },
|
|
69
|
+
{ field: "revocation_endpoint", required: false },
|
|
70
|
+
{ field: "introspection_endpoint", required: false },
|
|
71
|
+
{ field: "registration_endpoint", required: false }
|
|
72
|
+
];
|
|
73
|
+
function validateEndpointField(field, url, issuerOrigin) {
|
|
74
|
+
assertHttps(url, field);
|
|
75
|
+
if (new URL(url).origin !== issuerOrigin) {
|
|
76
|
+
throw new Error(`Discovery: ${field} "${url}" is not same-origin as issuer`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
62
79
|
function validateDiscoveryDocument(document, issuerUrl) {
|
|
63
80
|
assertHttps(issuerUrl, "issuer");
|
|
64
|
-
assertHttps(document.jwks_uri, "jwks_uri");
|
|
65
|
-
assertHttps(document.token_endpoint, "token_endpoint");
|
|
66
|
-
assertHttps(document.authorization_endpoint, "authorization_endpoint");
|
|
67
81
|
if (document.issuer !== issuerUrl) {
|
|
68
82
|
throw new Error(`Discovery: document issuer "${document.issuer}" does not match the configured issuer "${issuerUrl}"`);
|
|
69
83
|
}
|
|
70
84
|
const issuerOrigin = new URL(issuerUrl).origin;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
for (const { field, required } of ENDPOINT_FIELDS) {
|
|
86
|
+
const value = document[field];
|
|
87
|
+
if (value === void 0 && !required) continue;
|
|
88
|
+
if (typeof value !== "string") {
|
|
89
|
+
const requirement = required ? "is required and must be a string" : ", if present, must be a string";
|
|
90
|
+
throw new Error(`Discovery: ${field} ${requirement}`);
|
|
91
|
+
}
|
|
92
|
+
validateEndpointField(field, value, issuerOrigin);
|
|
79
93
|
}
|
|
80
94
|
}
|
|
81
95
|
async function fetchDiscovery(issuerUrl) {
|
|
@@ -86,7 +100,10 @@ async function fetchDiscovery(issuerUrl) {
|
|
|
86
100
|
}
|
|
87
101
|
const pending = discoveryPending.get(issuerUrl);
|
|
88
102
|
if (pending) return pending;
|
|
89
|
-
const promise = fetch(discoveryUrl(issuerUrl), {
|
|
103
|
+
const promise = fetch(discoveryUrl(issuerUrl), {
|
|
104
|
+
headers: { Accept: "application/json" },
|
|
105
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
106
|
+
}).then(
|
|
90
107
|
async (response) => {
|
|
91
108
|
if (!response.ok) {
|
|
92
109
|
throw new Error(`Discovery fetch for ${issuerUrl} failed: HTTP ${response.status}`);
|
|
@@ -143,6 +160,7 @@ function generateState() {
|
|
|
143
160
|
}
|
|
144
161
|
|
|
145
162
|
// src/token.ts
|
|
163
|
+
var FETCH_TIMEOUT_MS2 = 2500;
|
|
146
164
|
var TokenRequestError = class extends Error {
|
|
147
165
|
status;
|
|
148
166
|
error;
|
|
@@ -191,14 +209,29 @@ async function postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAut
|
|
|
191
209
|
} else {
|
|
192
210
|
body.set("client_id", clientId);
|
|
193
211
|
}
|
|
194
|
-
return fetch(tokenEndpoint, {
|
|
212
|
+
return fetch(tokenEndpoint, {
|
|
213
|
+
method: "POST",
|
|
214
|
+
headers,
|
|
215
|
+
body: body.toString(),
|
|
216
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
async function postTokenRequestOrThrow(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params) {
|
|
220
|
+
try {
|
|
221
|
+
return await postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params);
|
|
222
|
+
} catch (error) {
|
|
223
|
+
throw new TokenRequestError({
|
|
224
|
+
error: "network_failure",
|
|
225
|
+
errorDescription: error instanceof Error ? error.message : "Failed to reach the token endpoint"
|
|
226
|
+
});
|
|
227
|
+
}
|
|
195
228
|
}
|
|
196
229
|
async function readTokenResponseBody(response) {
|
|
197
230
|
return await response.json().catch(() => null);
|
|
198
231
|
}
|
|
199
232
|
async function exchangeAuthorizationCode(options) {
|
|
200
233
|
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
201
|
-
const response = await
|
|
234
|
+
const response = await postTokenRequestOrThrow(
|
|
202
235
|
discovery.token_endpoint,
|
|
203
236
|
options.clientId,
|
|
204
237
|
options.clientSecret,
|
package/dist/next.js
CHANGED
package/package.json
CHANGED