unjwt 0.7.2 → 0.8.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 +4 -4
- package/dist/THIRD-PARTY-LICENSES.md.gz +0 -0
- package/dist/_chunks/_codec-jwe.d.mts +170 -0
- package/dist/_chunks/_codec-jws.mjs +878 -0
- package/dist/_chunks/_internal.d.mts +7 -0
- package/dist/_chunks/_jwt-internal.mjs +388 -0
- package/dist/_chunks/algorithms.mjs +186 -0
- package/dist/_chunks/index.d.mts +512 -818
- package/dist/_chunks/index2.d.mts +11 -0
- package/dist/_chunks/index3.d.mts +108 -0
- package/dist/_chunks/jwe.d.mts +43 -66
- package/dist/_chunks/jwe.mjs +384 -252
- package/dist/_chunks/jwk.mjs +1390 -622
- package/dist/_chunks/jws.d.mts +48 -103
- package/dist/_chunks/jws.mjs +372 -184
- package/dist/_chunks/jwt.d.mts +56 -0
- package/dist/_chunks/libs/unsecure.d.mts +164 -85
- package/dist/_chunks/libs/unsecure.mjs +390 -123
- package/dist/adapters/elysia/index.d.mts +33 -171
- package/dist/adapters/elysia/index.mjs +106 -575
- package/dist/adapters/h3v1/index.d.mts +59 -344
- package/dist/adapters/h3v1/index.mjs +114 -619
- package/dist/adapters/h3v2/index.d.mts +58 -326
- package/dist/adapters/h3v2/index.mjs +108 -611
- package/dist/core/internal.d.mts +2 -0
- package/dist/core/internal.mjs +1 -0
- package/dist/core/jwe.d.mts +4 -2
- package/dist/core/jwe.mjs +4 -2
- package/dist/core/jwk.d.mts +183 -371
- package/dist/core/jwk.mjs +4 -3
- package/dist/core/jws.d.mts +4 -2
- package/dist/core/jws.mjs +4 -2
- package/dist/core/utils/index.d.mts +5 -155
- package/dist/core/utils/index.mjs +12 -3
- package/dist/index.d.mts +8 -4
- package/dist/index.mjs +6 -3
- package/package.json +39 -36
- package/dist/_chunks/_internal.mjs +0 -88
- package/dist/_chunks/utils.mjs +0 -390
package/dist/_chunks/utils.mjs
DELETED
|
@@ -1,390 +0,0 @@
|
|
|
1
|
-
import { base64UrlDecode, safeJsonParse, textDecoder, textEncoder } from "./libs/unsecure.mjs";
|
|
2
|
-
var JWTError = class extends Error {
|
|
3
|
-
code;
|
|
4
|
-
cause;
|
|
5
|
-
constructor(message, code, cause) {
|
|
6
|
-
super(message);
|
|
7
|
-
this.name = "JWTError";
|
|
8
|
-
this.code = code;
|
|
9
|
-
this.cause = cause;
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
function isJWTError(error, code) {
|
|
13
|
-
if (!(error instanceof JWTError)) return false;
|
|
14
|
-
return code === void 0 || error.code === code;
|
|
15
|
-
}
|
|
16
|
-
function inferJWSAllowedAlgorithms(key) {
|
|
17
|
-
if (!key || typeof key === "function") return void 0;
|
|
18
|
-
if (typeof key === "string" || key instanceof Uint8Array) return void 0;
|
|
19
|
-
if (typeof key !== "object") return void 0;
|
|
20
|
-
if (isCryptoKeyPair(key)) return inferJWSAllowedAlgorithms(key.publicKey);
|
|
21
|
-
if (isJWKSet(key)) return unionFromJWKSet(key.keys, jwsAlgsFromJWK);
|
|
22
|
-
if (isCryptoKey(key)) return jwsAlgsFromCryptoKey(key);
|
|
23
|
-
if (isJWK(key)) return jwsAlgsFromJWK(key);
|
|
24
|
-
}
|
|
25
|
-
function inferJWEAllowedAlgorithms(key) {
|
|
26
|
-
if (!key || typeof key === "function") return void 0;
|
|
27
|
-
if (typeof key === "string" || key instanceof Uint8Array) return [
|
|
28
|
-
"PBES2-HS256+A128KW",
|
|
29
|
-
"PBES2-HS384+A192KW",
|
|
30
|
-
"PBES2-HS512+A256KW",
|
|
31
|
-
"dir"
|
|
32
|
-
];
|
|
33
|
-
if (typeof key !== "object") return void 0;
|
|
34
|
-
if (isCryptoKeyPair(key)) return inferJWEAllowedAlgorithms(key.privateKey);
|
|
35
|
-
if (isJWKSet(key)) return unionFromJWKSet(key.keys, jweAlgsFromJWK);
|
|
36
|
-
if (isCryptoKey(key)) return jweAlgsFromCryptoKey(key);
|
|
37
|
-
if (isJWK(key)) return jweAlgsFromJWK(key);
|
|
38
|
-
}
|
|
39
|
-
function unionFromJWKSet(keys, mapper) {
|
|
40
|
-
const algs = /* @__PURE__ */ new Set();
|
|
41
|
-
for (const k of keys) {
|
|
42
|
-
const mapped = mapper(k);
|
|
43
|
-
if (!mapped) return void 0;
|
|
44
|
-
for (const a of mapped) algs.add(a);
|
|
45
|
-
}
|
|
46
|
-
return algs.size > 0 ? [...algs] : void 0;
|
|
47
|
-
}
|
|
48
|
-
function jwsAlgsFromJWK(jwk) {
|
|
49
|
-
if (jwk.alg) return [jwk.alg];
|
|
50
|
-
if (jwk.kty === "EC") {
|
|
51
|
-
const crv = jwk.crv;
|
|
52
|
-
if (crv === "P-256") return ["ES256"];
|
|
53
|
-
if (crv === "P-384") return ["ES384"];
|
|
54
|
-
if (crv === "P-521") return ["ES512"];
|
|
55
|
-
}
|
|
56
|
-
if (jwk.kty === "OKP") {
|
|
57
|
-
const crv = jwk.crv;
|
|
58
|
-
if (crv === "Ed25519") return ["Ed25519", "EdDSA"];
|
|
59
|
-
if (crv === "Ed448") return ["EdDSA"];
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
function jweAlgsFromJWK(jwk) {
|
|
63
|
-
if (jwk.kty === "oct") return jweAlgsFromOctJWK(jwk);
|
|
64
|
-
if (jwk.alg) return [jwk.alg];
|
|
65
|
-
if (jwk.kty === "EC") {
|
|
66
|
-
const crv = jwk.crv;
|
|
67
|
-
if (crv === "P-256" || crv === "P-384" || crv === "P-521") return [
|
|
68
|
-
"ECDH-ES",
|
|
69
|
-
"ECDH-ES+A128KW",
|
|
70
|
-
"ECDH-ES+A192KW",
|
|
71
|
-
"ECDH-ES+A256KW"
|
|
72
|
-
];
|
|
73
|
-
}
|
|
74
|
-
if (jwk.kty === "OKP") {
|
|
75
|
-
const crv = jwk.crv;
|
|
76
|
-
if (crv === "X25519" || crv === "X448") return [
|
|
77
|
-
"ECDH-ES",
|
|
78
|
-
"ECDH-ES+A128KW",
|
|
79
|
-
"ECDH-ES+A192KW",
|
|
80
|
-
"ECDH-ES+A256KW"
|
|
81
|
-
];
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
function jweAlgsFromOctJWK(jwk) {
|
|
85
|
-
const alg = jwk.alg;
|
|
86
|
-
if (!alg) return void 0;
|
|
87
|
-
if (alg === "A128GCM") return ["A128GCMKW", "dir"];
|
|
88
|
-
if (alg === "A192GCM") return ["A192GCMKW", "dir"];
|
|
89
|
-
if (alg === "A256GCM") return ["A256GCMKW", "dir"];
|
|
90
|
-
if (alg === "A128KW" || alg === "A192KW" || alg === "A256KW") return [alg, "dir"];
|
|
91
|
-
if (alg === "A128GCMKW" || alg === "A192GCMKW" || alg === "A256GCMKW") return [alg, "dir"];
|
|
92
|
-
if (alg === "A128CBC-HS256" || alg === "A192CBC-HS384" || alg === "A256CBC-HS512") return ["dir"];
|
|
93
|
-
if (alg === "dir") return ["dir"];
|
|
94
|
-
return [alg];
|
|
95
|
-
}
|
|
96
|
-
function jwsAlgsFromCryptoKey(key) {
|
|
97
|
-
const name = key.algorithm.name;
|
|
98
|
-
const hashName = key.algorithm.hash?.name;
|
|
99
|
-
const hashBits = hashName?.startsWith("SHA-") ? hashName.slice(4) : void 0;
|
|
100
|
-
switch (name) {
|
|
101
|
-
case "HMAC": return hashBits ? [`HS${hashBits}`] : void 0;
|
|
102
|
-
case "RSASSA-PKCS1-v1_5": return hashBits ? [`RS${hashBits}`] : void 0;
|
|
103
|
-
case "RSA-PSS": return hashBits ? [`PS${hashBits}`] : void 0;
|
|
104
|
-
case "ECDSA": {
|
|
105
|
-
const curve = key.algorithm.namedCurve;
|
|
106
|
-
if (curve === "P-256") return ["ES256"];
|
|
107
|
-
if (curve === "P-384") return ["ES384"];
|
|
108
|
-
if (curve === "P-521") return ["ES512"];
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
case "Ed25519": return ["Ed25519", "EdDSA"];
|
|
112
|
-
default: return;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
function jweAlgsFromCryptoKey(key) {
|
|
116
|
-
const name = key.algorithm.name;
|
|
117
|
-
const hashName = key.algorithm.hash?.name;
|
|
118
|
-
const length = key.algorithm.length;
|
|
119
|
-
switch (name) {
|
|
120
|
-
case "AES-KW":
|
|
121
|
-
if (length === 128) return ["A128KW", "dir"];
|
|
122
|
-
if (length === 192) return ["A192KW", "dir"];
|
|
123
|
-
if (length === 256) return ["A256KW", "dir"];
|
|
124
|
-
return;
|
|
125
|
-
case "AES-GCM":
|
|
126
|
-
if (length === 128) return ["A128GCMKW", "dir"];
|
|
127
|
-
if (length === 192) return ["A192GCMKW", "dir"];
|
|
128
|
-
if (length === 256) return ["A256GCMKW", "dir"];
|
|
129
|
-
return;
|
|
130
|
-
case "RSA-OAEP":
|
|
131
|
-
if (hashName === "SHA-1") return ["RSA-OAEP"];
|
|
132
|
-
if (hashName === "SHA-256") return ["RSA-OAEP-256"];
|
|
133
|
-
if (hashName === "SHA-384") return ["RSA-OAEP-384"];
|
|
134
|
-
if (hashName === "SHA-512") return ["RSA-OAEP-512"];
|
|
135
|
-
return;
|
|
136
|
-
case "ECDH":
|
|
137
|
-
case "X25519":
|
|
138
|
-
case "X448": return [
|
|
139
|
-
"ECDH-ES",
|
|
140
|
-
"ECDH-ES+A128KW",
|
|
141
|
-
"ECDH-ES+A192KW",
|
|
142
|
-
"ECDH-ES+A256KW"
|
|
143
|
-
];
|
|
144
|
-
default: return;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
function applyTypCtyDefaults(header, payload) {
|
|
148
|
-
if (!(typeof payload === "object" && payload !== null && !(payload instanceof Uint8Array))) return header;
|
|
149
|
-
let typ = header.typ;
|
|
150
|
-
if (typ === void 0) header.typ = typ = "JWT";
|
|
151
|
-
if (typ === "JWT" || typ === "jwt" || typ.toLowerCase().includes("jwt")) header.cty ||= "application/json";
|
|
152
|
-
return header;
|
|
153
|
-
}
|
|
154
|
-
function isJWTContent(header) {
|
|
155
|
-
if (!header) return false;
|
|
156
|
-
if (header.typ?.toLowerCase().includes("jwt")) return true;
|
|
157
|
-
const cty = header.cty?.toLowerCase();
|
|
158
|
-
return cty === "json" || cty === "application/json" || !!cty && cty.endsWith("+json");
|
|
159
|
-
}
|
|
160
|
-
function decodeMaybeJWTString(decodedString) {
|
|
161
|
-
if (decodedString.startsWith("{") && decodedString.endsWith("}") || decodedString.startsWith("[") && decodedString.endsWith("]")) try {
|
|
162
|
-
return safeJsonParse(decodedString);
|
|
163
|
-
} catch {}
|
|
164
|
-
return decodedString;
|
|
165
|
-
}
|
|
166
|
-
function decodePayloadFromBytes(bytes, forceUint8Array) {
|
|
167
|
-
if (forceUint8Array) return bytes;
|
|
168
|
-
return decodeMaybeJWTString(textDecoder.decode(bytes));
|
|
169
|
-
}
|
|
170
|
-
function decodePayloadFromB64UrlSegment(payloadEncoded, forceUint8Array) {
|
|
171
|
-
if (forceUint8Array) return base64UrlDecode(payloadEncoded, { returnAs: "uint8array" });
|
|
172
|
-
return decodeMaybeJWTString(base64UrlDecode(payloadEncoded));
|
|
173
|
-
}
|
|
174
|
-
function getPlaintextBytes(payload) {
|
|
175
|
-
if (payload instanceof Uint8Array) return payload;
|
|
176
|
-
if (typeof payload === "string") return textEncoder.encode(payload);
|
|
177
|
-
if (typeof payload === "object" && payload !== null) return textEncoder.encode(JSON.stringify(payload));
|
|
178
|
-
throw new TypeError("Plaintext must be a string, Uint8Array, or a JSON-serializable object.");
|
|
179
|
-
}
|
|
180
|
-
const TIME_CONSTANTS = Object.freeze({
|
|
181
|
-
s: 1,
|
|
182
|
-
second: 1,
|
|
183
|
-
seconds: 1,
|
|
184
|
-
m: 60,
|
|
185
|
-
minute: 60,
|
|
186
|
-
minutes: 60,
|
|
187
|
-
h: 3600,
|
|
188
|
-
hour: 3600,
|
|
189
|
-
hours: 3600,
|
|
190
|
-
D: 86400,
|
|
191
|
-
day: 86400,
|
|
192
|
-
days: 86400,
|
|
193
|
-
W: 604800,
|
|
194
|
-
week: 604800,
|
|
195
|
-
weeks: 604800,
|
|
196
|
-
M: 2592e3,
|
|
197
|
-
month: 2592e3,
|
|
198
|
-
months: 2592e3,
|
|
199
|
-
Y: 31536e3,
|
|
200
|
-
year: 31536e3,
|
|
201
|
-
years: 31536e3
|
|
202
|
-
});
|
|
203
|
-
const DURATION_REGEX = /^(\d+)(s|second|seconds|m|minute|minutes|h|hour|hours|D|day|days|W|week|weeks|M|month|months|Y|year|years)?$/;
|
|
204
|
-
function _parseDurationSeconds(value) {
|
|
205
|
-
if (typeof value === "number") {
|
|
206
|
-
if (!Number.isInteger(value)) throw new TypeError("Duration must be an integer number of seconds.");
|
|
207
|
-
return value;
|
|
208
|
-
}
|
|
209
|
-
if (typeof value === "string") {
|
|
210
|
-
const match = value.match(DURATION_REGEX);
|
|
211
|
-
if (!match || !match[1]) throw new TypeError("Invalid duration format. Must be an integer or a string like '10m', '2h', '7D', etc.");
|
|
212
|
-
return Number.parseInt(match[1], 10) * TIME_CONSTANTS[match[2] || "s"];
|
|
213
|
-
}
|
|
214
|
-
throw new TypeError("Duration must be a number or a string representing time.");
|
|
215
|
-
}
|
|
216
|
-
function computeDurationInSeconds(duration) {
|
|
217
|
-
const seconds = _parseDurationSeconds(duration);
|
|
218
|
-
if (seconds <= 0) throw new TypeError("Duration must be a positive integer number of seconds.");
|
|
219
|
-
return seconds;
|
|
220
|
-
}
|
|
221
|
-
const computeExpiresInSeconds = computeDurationInSeconds;
|
|
222
|
-
const computeMaxTokenAgeSeconds = computeDurationInSeconds;
|
|
223
|
-
function computeJwtTimeClaims(payload, options) {
|
|
224
|
-
const { currentDate, expiresIn, expiresAt, notBeforeIn, notBeforeAt } = options ?? {};
|
|
225
|
-
if (expiresIn !== void 0 && expiresAt !== void 0) throw new JWTError("\"expiresIn\" and \"expiresAt\" are mutually exclusive; pass only one.", "ERR_JWT_CLAIM_INVALID");
|
|
226
|
-
if (notBeforeIn !== void 0 && notBeforeAt !== void 0) throw new JWTError("\"notBeforeIn\" and \"notBeforeAt\" are mutually exclusive; pass only one.", "ERR_JWT_CLAIM_INVALID");
|
|
227
|
-
const hasExpHint = expiresIn !== void 0 || expiresAt !== void 0;
|
|
228
|
-
const hasNbfHint = notBeforeIn !== void 0 || notBeforeAt !== void 0;
|
|
229
|
-
if (!hasExpHint && !hasNbfHint) return void 0;
|
|
230
|
-
if (!payload || typeof payload !== "object" || payload instanceof Uint8Array) return void 0;
|
|
231
|
-
const typedPayload = payload;
|
|
232
|
-
const wantsExp = hasExpHint && typedPayload.exp === void 0;
|
|
233
|
-
const wantsNbf = hasNbfHint && typedPayload.nbf === void 0;
|
|
234
|
-
if (!wantsExp && !wantsNbf) return void 0;
|
|
235
|
-
const now = Math.round((currentDate ?? /* @__PURE__ */ new Date()).getTime() / 1e3);
|
|
236
|
-
const claims = { ...typedPayload };
|
|
237
|
-
claims.iat ||= now;
|
|
238
|
-
if (wantsExp) if (expiresAt !== void 0) {
|
|
239
|
-
const expMs = expiresAt.getTime();
|
|
240
|
-
if (!Number.isFinite(expMs)) throw new JWTError("\"expiresAt\" must be a valid Date.", "ERR_JWT_CLAIM_INVALID");
|
|
241
|
-
claims.exp = Math.floor(expMs / 1e3);
|
|
242
|
-
} else claims.exp = claims.iat + computeDurationInSeconds(expiresIn);
|
|
243
|
-
if (wantsNbf) if (notBeforeAt !== void 0) {
|
|
244
|
-
const nbfMs = notBeforeAt.getTime();
|
|
245
|
-
if (!Number.isFinite(nbfMs)) throw new JWTError("\"notBeforeAt\" must be a valid Date.", "ERR_JWT_CLAIM_INVALID");
|
|
246
|
-
claims.nbf = Math.floor(nbfMs / 1e3);
|
|
247
|
-
} else {
|
|
248
|
-
const offset = _parseDurationSeconds(notBeforeIn);
|
|
249
|
-
if (offset < 0) throw new JWTError("\"notBeforeIn\" must be zero or a positive duration.", "ERR_JWT_CLAIM_INVALID");
|
|
250
|
-
claims.nbf = claims.iat + offset;
|
|
251
|
-
}
|
|
252
|
-
return claims;
|
|
253
|
-
}
|
|
254
|
-
function validateJwtClaims(jwtClaims, options = {}) {
|
|
255
|
-
const clockTolerance = options.clockTolerance ?? 0;
|
|
256
|
-
const currentTime = Math.round((options.currentDate ?? /* @__PURE__ */ new Date()).getTime() / 1e3);
|
|
257
|
-
if (options.requiredClaims || options.issuer || options.audience || options.subject || options.maxTokenAge) {
|
|
258
|
-
const allRequiredClaims = new Set(options.requiredClaims || []);
|
|
259
|
-
if (options.issuer) allRequiredClaims.add("iss");
|
|
260
|
-
if (options.audience) allRequiredClaims.add("aud");
|
|
261
|
-
if (options.subject) allRequiredClaims.add("sub");
|
|
262
|
-
if (options.maxTokenAge) allRequiredClaims.add("iat");
|
|
263
|
-
const missingClaims = [];
|
|
264
|
-
for (const claimName of allRequiredClaims) if (!(claimName in jwtClaims)) missingClaims.push(claimName);
|
|
265
|
-
if (missingClaims.length > 0) throw new JWTError(`Missing required JWT Claims: ${missingClaims.join(", ")}`, "ERR_JWT_CLAIM_MISSING");
|
|
266
|
-
}
|
|
267
|
-
if (jwtClaims.exp !== void 0 && !Number.isFinite(jwtClaims.exp)) throw new JWTError("JWT \"exp\" (Expiration Time) Claim must be a number.", "ERR_JWT_CLAIM_INVALID");
|
|
268
|
-
if (jwtClaims.nbf !== void 0 && !Number.isFinite(jwtClaims.nbf)) throw new JWTError("JWT \"nbf\" (Not Before) Claim must be a number.", "ERR_JWT_CLAIM_INVALID");
|
|
269
|
-
if (jwtClaims.iat !== void 0 && !Number.isFinite(jwtClaims.iat)) throw new JWTError("JWT \"iat\" (Issued At) Claim must be a number.", "ERR_JWT_CLAIM_INVALID");
|
|
270
|
-
if (options.issuer) {
|
|
271
|
-
const expectedIssuers = maybeArray(options.issuer);
|
|
272
|
-
if (!jwtClaims.iss || !expectedIssuers.includes(jwtClaims.iss)) throw new JWTError(`Invalid JWT "iss" (Issuer) Claim: Expected ${expectedIssuers.join(" or ")}, got ${jwtClaims.iss}`, "ERR_JWT_CLAIM_INVALID");
|
|
273
|
-
}
|
|
274
|
-
if (options.subject && jwtClaims.sub !== options.subject) throw new JWTError(`Invalid JWT "sub" (Subject) Claim: Expected ${options.subject}, got ${jwtClaims.sub}`, "ERR_JWT_CLAIM_INVALID");
|
|
275
|
-
if (options.audience) {
|
|
276
|
-
const expectedAudiences = maybeArray(options.audience);
|
|
277
|
-
const claimAudience = maybeArray(jwtClaims.aud || []);
|
|
278
|
-
if (!claimAudience.some((aud) => expectedAudiences.includes(aud))) throw new JWTError(`Invalid JWT "aud" (Audience) Claim: Expected ${expectedAudiences.join(" or ")}, got ${claimAudience.join(", ")}`, "ERR_JWT_CLAIM_INVALID");
|
|
279
|
-
}
|
|
280
|
-
if (typeof jwtClaims.nbf === "number" && jwtClaims.nbf > currentTime + clockTolerance) throw new JWTError(`JWT "nbf" (Not Before) Claim validation failed: Token is not yet valid (nbf: ${(/* @__PURE__ */ new Date(jwtClaims.nbf * 1e3)).toISOString()})`, "ERR_JWT_NBF");
|
|
281
|
-
if (typeof jwtClaims.exp === "number" && jwtClaims.exp <= currentTime - clockTolerance) throw new JWTError(`JWT "exp" (Expiration Time) Claim validation failed: Token has expired (exp: ${(/* @__PURE__ */ new Date(jwtClaims.exp * 1e3)).toISOString()})`, "ERR_JWT_EXPIRED", {
|
|
282
|
-
jti: jwtClaims.jti,
|
|
283
|
-
iat: jwtClaims.iat,
|
|
284
|
-
exp: jwtClaims.exp
|
|
285
|
-
});
|
|
286
|
-
if (options.maxTokenAge) {
|
|
287
|
-
if (typeof jwtClaims.iat !== "number") throw new JWTError("JWT \"iat\" (Issued At) Claim must be a number when maxTokenAge is set.", "ERR_JWT_CLAIM_INVALID");
|
|
288
|
-
if (jwtClaims.iat > currentTime + clockTolerance) throw new JWTError(`JWT "iat" (Issued At) Claim validation failed: Token was issued in the future (iat: ${(/* @__PURE__ */ new Date(jwtClaims.iat * 1e3)).toISOString()})`, "ERR_JWT_CLAIM_INVALID");
|
|
289
|
-
if (jwtClaims.iat < currentTime - computeDurationInSeconds(options.maxTokenAge) - clockTolerance) throw new JWTError(`JWT "iat" (Issued At) Claim validation failed: Token is too old (maxTokenAge: ${options.maxTokenAge}s, iat: ${(/* @__PURE__ */ new Date(jwtClaims.iat * 1e3)).toISOString()})`, "ERR_JWT_EXPIRED", {
|
|
290
|
-
jti: jwtClaims.jti,
|
|
291
|
-
iat: jwtClaims.iat,
|
|
292
|
-
exp: jwtClaims.exp
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
const BASE_PROCESSED_JWS = [
|
|
297
|
-
"alg",
|
|
298
|
-
"typ",
|
|
299
|
-
"cty",
|
|
300
|
-
"kid",
|
|
301
|
-
"b64"
|
|
302
|
-
];
|
|
303
|
-
const BASE_PROCESSED_JWE = [
|
|
304
|
-
"alg",
|
|
305
|
-
"enc",
|
|
306
|
-
"typ",
|
|
307
|
-
"cty",
|
|
308
|
-
"kid",
|
|
309
|
-
"iv",
|
|
310
|
-
"tag",
|
|
311
|
-
"p2s",
|
|
312
|
-
"p2c",
|
|
313
|
-
"epk",
|
|
314
|
-
"apu",
|
|
315
|
-
"apv"
|
|
316
|
-
];
|
|
317
|
-
function validateCriticalHeadersJWS(protectedHeader, recognizedHeaders = []) {
|
|
318
|
-
if (!protectedHeader.crit) return;
|
|
319
|
-
const missingHeaderParams = /* @__PURE__ */ new Set();
|
|
320
|
-
const recognizedParams = new Set([...recognizedHeaders, ...BASE_PROCESSED_JWS]);
|
|
321
|
-
for (const param of protectedHeader.crit) {
|
|
322
|
-
if (recognizedParams.has(param) && (param in protectedHeader || param === "b64")) continue;
|
|
323
|
-
missingHeaderParams.add(param);
|
|
324
|
-
}
|
|
325
|
-
if (missingHeaderParams.size > 0) throw new JWTError(`Missing critical header parameters: ${[...missingHeaderParams].join(", ")}`, "ERR_JWS_INVALID");
|
|
326
|
-
}
|
|
327
|
-
function validateCriticalHeadersJWE(protectedHeader, recognizedHeaders) {
|
|
328
|
-
if (!protectedHeader.crit) return;
|
|
329
|
-
const understoodParams = new Set([...recognizedHeaders || [], ...BASE_PROCESSED_JWE]);
|
|
330
|
-
for (const critParam of protectedHeader.crit) {
|
|
331
|
-
if (!Object.prototype.hasOwnProperty.call(protectedHeader, critParam)) throw new JWTError(`Critical header parameter "${critParam}" listed in "crit" but not present in the protected header.`, "ERR_JWE_INVALID");
|
|
332
|
-
if (!understoodParams.has(critParam)) throw new JWTError(`Unprocessed critical header parameters: ${critParam}`, "ERR_JWE_INVALID");
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
function concatUint8Arrays(...arrays) {
|
|
336
|
-
const totalLength = arrays.reduce((length, arr) => length + arr.length, 0);
|
|
337
|
-
const result = new Uint8Array(totalLength);
|
|
338
|
-
let offset = 0;
|
|
339
|
-
for (const arr of arrays) {
|
|
340
|
-
result.set(arr, offset);
|
|
341
|
-
offset += arr.length;
|
|
342
|
-
}
|
|
343
|
-
return result;
|
|
344
|
-
}
|
|
345
|
-
function maybeArray(item) {
|
|
346
|
-
return Array.isArray(item) ? item : [item];
|
|
347
|
-
}
|
|
348
|
-
function isJWK(key) {
|
|
349
|
-
return typeof key === "object" && key !== null && "kty" in key && typeof key.kty === "string";
|
|
350
|
-
}
|
|
351
|
-
function isJWKSet(key) {
|
|
352
|
-
return key && typeof key === "object" && "keys" in key && Array.isArray(key.keys);
|
|
353
|
-
}
|
|
354
|
-
function assertCryptoKey(key) {
|
|
355
|
-
if (!isCryptoKey(key)) throw new Error("CryptoKey instance expected");
|
|
356
|
-
}
|
|
357
|
-
function isCryptoKey(key) {
|
|
358
|
-
return key?.[Symbol.toStringTag] === "CryptoKey";
|
|
359
|
-
}
|
|
360
|
-
const isCryptoKeyPair = (key) => key && typeof key === "object" && isCryptoKey(key.publicKey) && isCryptoKey(key.privateKey);
|
|
361
|
-
function isSymmetricJWK(key) {
|
|
362
|
-
return isJWK(key) && key.kty === "oct" && typeof key.k === "string";
|
|
363
|
-
}
|
|
364
|
-
function isAsymmetricJWK(key) {
|
|
365
|
-
return !isSymmetricJWK(key);
|
|
366
|
-
}
|
|
367
|
-
function isPrivateJWK(key) {
|
|
368
|
-
if (!isJWK(key)) return false;
|
|
369
|
-
if (key.kty === "EC") return typeof key.d === "string";
|
|
370
|
-
if (key.kty === "OKP") return typeof key.d === "string";
|
|
371
|
-
if (key.kty === "RSA") return typeof key.d === "string";
|
|
372
|
-
return false;
|
|
373
|
-
}
|
|
374
|
-
function isPublicJWK(key) {
|
|
375
|
-
if (!isJWK(key)) return false;
|
|
376
|
-
if (key.kty === "EC") {
|
|
377
|
-
const ec = key;
|
|
378
|
-
return typeof ec.x === "string" && typeof ec.y === "string" && typeof ec.d !== "string";
|
|
379
|
-
}
|
|
380
|
-
if (key.kty === "OKP") {
|
|
381
|
-
const okp = key;
|
|
382
|
-
return typeof okp.x === "string" && typeof okp.d !== "string";
|
|
383
|
-
}
|
|
384
|
-
if (key.kty === "RSA") {
|
|
385
|
-
const rsa = key;
|
|
386
|
-
return typeof rsa.n === "string" && typeof rsa.e === "string" && typeof rsa.d !== "string";
|
|
387
|
-
}
|
|
388
|
-
return false;
|
|
389
|
-
}
|
|
390
|
-
export { JWTError, applyTypCtyDefaults, assertCryptoKey, computeDurationInSeconds, computeExpiresInSeconds, computeJwtTimeClaims, computeMaxTokenAgeSeconds, concatUint8Arrays, decodeMaybeJWTString, decodePayloadFromB64UrlSegment, decodePayloadFromBytes, getPlaintextBytes, inferJWEAllowedAlgorithms, inferJWSAllowedAlgorithms, isAsymmetricJWK, isCryptoKey, isCryptoKeyPair, isJWK, isJWKSet, isJWTContent, isJWTError, isPrivateJWK, isPublicJWK, isSymmetricJWK, maybeArray, validateCriticalHeadersJWE, validateCriticalHeadersJWS, validateJwtClaims };
|