lacewing 1.0.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.
Files changed (141) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +9 -0
  3. package/NOTICE.md +1 -0
  4. package/README.md +313 -0
  5. package/dist/index.js +40 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/src/cookbook/access-refresh.js +86 -0
  8. package/dist/src/cookbook/access-refresh.js.map +1 -0
  9. package/dist/src/http/bearer.js +44 -0
  10. package/dist/src/http/bearer.js.map +1 -0
  11. package/dist/src/http/cookies.js +96 -0
  12. package/dist/src/http/cookies.js.map +1 -0
  13. package/dist/src/jwks/local.js +85 -0
  14. package/dist/src/jwks/local.js.map +1 -0
  15. package/dist/src/jwks/remote.js +121 -0
  16. package/dist/src/jwks/remote.js.map +1 -0
  17. package/dist/src/jwt/decrypt.js +126 -0
  18. package/dist/src/jwt/decrypt.js.map +1 -0
  19. package/dist/src/jwt/decryption_profile.js +78 -0
  20. package/dist/src/jwt/decryption_profile.js.map +1 -0
  21. package/dist/src/jwt/encrypt.js +149 -0
  22. package/dist/src/jwt/encrypt.js.map +1 -0
  23. package/dist/src/jwt/profile.js +102 -0
  24. package/dist/src/jwt/profile.js.map +1 -0
  25. package/dist/src/jwt/sign.js +173 -0
  26. package/dist/src/jwt/sign.js.map +1 -0
  27. package/dist/src/jwt/verify.js +118 -0
  28. package/dist/src/jwt/verify.js.map +1 -0
  29. package/dist/src/key/encryption.js +132 -0
  30. package/dist/src/key/encryption.js.map +1 -0
  31. package/dist/src/key/export.js +46 -0
  32. package/dist/src/key/export.js.map +1 -0
  33. package/dist/src/key/generate.js +47 -0
  34. package/dist/src/key/generate.js.map +1 -0
  35. package/dist/src/key/import.js +136 -0
  36. package/dist/src/key/import.js.map +1 -0
  37. package/dist/src/legacy/rs256.js +11 -0
  38. package/dist/src/legacy/rs256.js.map +1 -0
  39. package/dist/src/legacy/rsa.js +37 -0
  40. package/dist/src/legacy/rsa.js.map +1 -0
  41. package/dist/src/lib/algorithms.js +60 -0
  42. package/dist/src/lib/algorithms.js.map +1 -0
  43. package/dist/src/lib/base64url.js +28 -0
  44. package/dist/src/lib/base64url.js.map +1 -0
  45. package/dist/src/lib/claims.js +111 -0
  46. package/dist/src/lib/claims.js.map +1 -0
  47. package/dist/src/lib/duration.js +24 -0
  48. package/dist/src/lib/duration.js.map +1 -0
  49. package/dist/src/lib/entropy.js +70 -0
  50. package/dist/src/lib/entropy.js.map +1 -0
  51. package/dist/src/lib/headers.js +75 -0
  52. package/dist/src/lib/headers.js.map +1 -0
  53. package/dist/src/lib/invariants.js +12 -0
  54. package/dist/src/lib/invariants.js.map +1 -0
  55. package/dist/src/lib/json.js +140 -0
  56. package/dist/src/lib/json.js.map +1 -0
  57. package/dist/src/lib/jwe_algorithms.js +81 -0
  58. package/dist/src/lib/jwe_algorithms.js.map +1 -0
  59. package/dist/src/lib/payload_hygiene.js +116 -0
  60. package/dist/src/lib/payload_hygiene.js.map +1 -0
  61. package/dist/src/lib/utf8.js +27 -0
  62. package/dist/src/lib/utf8.js.map +1 -0
  63. package/dist/src/revocation/memory.js +67 -0
  64. package/dist/src/revocation/memory.js.map +1 -0
  65. package/dist/src/revocation/store.js +25 -0
  66. package/dist/src/revocation/store.js.map +1 -0
  67. package/dist/src/types.js +51 -0
  68. package/dist/src/types.js.map +1 -0
  69. package/dist/src/util/errors.js +96 -0
  70. package/dist/src/util/errors.js.map +1 -0
  71. package/dist/src/util/unsafe-decode.js +45 -0
  72. package/dist/src/util/unsafe-decode.js.map +1 -0
  73. package/dist/types/index.d.ts +29 -0
  74. package/dist/types/index.d.ts.map +1 -0
  75. package/dist/types/src/cookbook/access-refresh.d.ts +77 -0
  76. package/dist/types/src/cookbook/access-refresh.d.ts.map +1 -0
  77. package/dist/types/src/http/bearer.d.ts +20 -0
  78. package/dist/types/src/http/bearer.d.ts.map +1 -0
  79. package/dist/types/src/http/cookies.d.ts +38 -0
  80. package/dist/types/src/http/cookies.d.ts.map +1 -0
  81. package/dist/types/src/jwks/local.d.ts +16 -0
  82. package/dist/types/src/jwks/local.d.ts.map +1 -0
  83. package/dist/types/src/jwks/remote.d.ts +23 -0
  84. package/dist/types/src/jwks/remote.d.ts.map +1 -0
  85. package/dist/types/src/jwt/decrypt.d.ts +23 -0
  86. package/dist/types/src/jwt/decrypt.d.ts.map +1 -0
  87. package/dist/types/src/jwt/decryption_profile.d.ts +32 -0
  88. package/dist/types/src/jwt/decryption_profile.d.ts.map +1 -0
  89. package/dist/types/src/jwt/encrypt.d.ts +34 -0
  90. package/dist/types/src/jwt/encrypt.d.ts.map +1 -0
  91. package/dist/types/src/jwt/profile.d.ts +37 -0
  92. package/dist/types/src/jwt/profile.d.ts.map +1 -0
  93. package/dist/types/src/jwt/sign.d.ts +59 -0
  94. package/dist/types/src/jwt/sign.d.ts.map +1 -0
  95. package/dist/types/src/jwt/verify.d.ts +41 -0
  96. package/dist/types/src/jwt/verify.d.ts.map +1 -0
  97. package/dist/types/src/key/encryption.d.ts +37 -0
  98. package/dist/types/src/key/encryption.d.ts.map +1 -0
  99. package/dist/types/src/key/export.d.ts +10 -0
  100. package/dist/types/src/key/export.d.ts.map +1 -0
  101. package/dist/types/src/key/generate.d.ts +27 -0
  102. package/dist/types/src/key/generate.d.ts.map +1 -0
  103. package/dist/types/src/key/import.d.ts +20 -0
  104. package/dist/types/src/key/import.d.ts.map +1 -0
  105. package/dist/types/src/legacy/rs256.d.ts +11 -0
  106. package/dist/types/src/legacy/rs256.d.ts.map +1 -0
  107. package/dist/types/src/legacy/rsa.d.ts +25 -0
  108. package/dist/types/src/legacy/rsa.d.ts.map +1 -0
  109. package/dist/types/src/lib/algorithms.d.ts +34 -0
  110. package/dist/types/src/lib/algorithms.d.ts.map +1 -0
  111. package/dist/types/src/lib/base64url.d.ts +8 -0
  112. package/dist/types/src/lib/base64url.d.ts.map +1 -0
  113. package/dist/types/src/lib/claims.d.ts +15 -0
  114. package/dist/types/src/lib/claims.d.ts.map +1 -0
  115. package/dist/types/src/lib/duration.d.ts +7 -0
  116. package/dist/types/src/lib/duration.d.ts.map +1 -0
  117. package/dist/types/src/lib/entropy.d.ts +21 -0
  118. package/dist/types/src/lib/entropy.d.ts.map +1 -0
  119. package/dist/types/src/lib/headers.d.ts +19 -0
  120. package/dist/types/src/lib/headers.d.ts.map +1 -0
  121. package/dist/types/src/lib/invariants.d.ts +6 -0
  122. package/dist/types/src/lib/invariants.d.ts.map +1 -0
  123. package/dist/types/src/lib/json.d.ts +24 -0
  124. package/dist/types/src/lib/json.d.ts.map +1 -0
  125. package/dist/types/src/lib/jwe_algorithms.d.ts +46 -0
  126. package/dist/types/src/lib/jwe_algorithms.d.ts.map +1 -0
  127. package/dist/types/src/lib/payload_hygiene.d.ts +20 -0
  128. package/dist/types/src/lib/payload_hygiene.d.ts.map +1 -0
  129. package/dist/types/src/lib/utf8.d.ts +7 -0
  130. package/dist/types/src/lib/utf8.d.ts.map +1 -0
  131. package/dist/types/src/revocation/memory.d.ts +22 -0
  132. package/dist/types/src/revocation/memory.d.ts.map +1 -0
  133. package/dist/types/src/revocation/store.d.ts +17 -0
  134. package/dist/types/src/revocation/store.d.ts.map +1 -0
  135. package/dist/types/src/types.d.ts +196 -0
  136. package/dist/types/src/types.d.ts.map +1 -0
  137. package/dist/types/src/util/errors.d.ts +89 -0
  138. package/dist/types/src/util/errors.d.ts.map +1 -0
  139. package/dist/types/src/util/unsafe-decode.d.ts +21 -0
  140. package/dist/types/src/util/unsafe-decode.d.ts.map +1 -0
  141. package/package.json +70 -0
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Verification profiles - the RFC 8725 §3.12 mechanism and the library's
3
+ * signature API.
4
+ *
5
+ * A profile is the *only* argument shape `jwtVerify` accepts, which makes
6
+ * `typ`, issuer, audience, and the algorithm allowlist structurally
7
+ * mandatory. The key source belongs to the profile, which belongs to an
8
+ * issuer - that is the §3.8 issuer-to-key binding.
9
+ */
10
+ import { toValidAlg } from "../lib/algorithms.js";
11
+ import { parseDuration } from "../lib/duration.js";
12
+ import { createLocalJWKSet } from "../jwks/local.js";
13
+ import { createRemoteJWKSet } from "../jwks/remote.js";
14
+ import { isLacewingKey, toSeconds, } from "../types.js";
15
+ const DEFAULT_CLOCK_SKEW_SECONDS = 5;
16
+ const MAX_CLOCK_SKEW_SECONDS = 120;
17
+ function requireNonEmptyString(value, field) {
18
+ if (typeof value !== "string" || value.length === 0) {
19
+ throw new TypeError(`Profile "${field}" must be a non-empty string`);
20
+ }
21
+ return value;
22
+ }
23
+ function normalizeKeys(keys, algorithms) {
24
+ if (isLacewingKey(keys)) {
25
+ if (keys.keyType === "private") {
26
+ throw new TypeError("Profiles verify tokens - pass the public key, not the private key");
27
+ }
28
+ if (!algorithms.includes(keys.algorithm)) {
29
+ throw new TypeError("The profile key's algorithm is not in the profile's allowlist");
30
+ }
31
+ return keys;
32
+ }
33
+ if (typeof keys === "object" && keys !== null) {
34
+ if (typeof keys.getVerificationKey === "function") {
35
+ return keys;
36
+ }
37
+ if (Array.isArray(keys.keys)) {
38
+ return createLocalJWKSet(keys);
39
+ }
40
+ if (typeof keys.jwksUri === "string") {
41
+ const remote = keys;
42
+ return createRemoteJWKSet(remote.jwksUri, {
43
+ cacheTtlSeconds: remote.cacheTtlSeconds,
44
+ cooldownSeconds: remote.cooldownSeconds,
45
+ timeoutMs: remote.timeoutMs,
46
+ });
47
+ }
48
+ }
49
+ throw new TypeError("Profile keys must be a JWKS document, a { jwksUri } config, a KeySource, or an imported key");
50
+ }
51
+ /** Build the security boundary that `jwtVerify` enforces. */
52
+ export function defineProfile(options) {
53
+ const typ = requireNonEmptyString(options.typ, "typ");
54
+ const iss = requireNonEmptyString(options.issuer, "issuer");
55
+ const aud = requireNonEmptyString(options.audience, "audience");
56
+ if (!Array.isArray(options.algorithms) || options.algorithms.length === 0) {
57
+ throw new TypeError("Profile requires a non-empty algorithm allowlist");
58
+ }
59
+ const alg = Object.freeze(options.algorithms.map((name) => toValidAlg(name)));
60
+ const maxTokenAge = parseDuration(options.maxTokenAge);
61
+ if (maxTokenAge < 1) {
62
+ throw new TypeError("Profile maxTokenAge must be at least one second");
63
+ }
64
+ const maxClockSkew = parseDuration(options.maxClockSkew ?? DEFAULT_CLOCK_SKEW_SECONDS);
65
+ if (maxClockSkew > MAX_CLOCK_SKEW_SECONDS) {
66
+ throw new TypeError(`Profile maxClockSkew is capped at ${MAX_CLOCK_SKEW_SECONDS} seconds`);
67
+ }
68
+ if (options.revocation !== undefined && typeof options.revocation.isRevoked !== "function") {
69
+ throw new TypeError("Profile revocation store must implement isRevoked()");
70
+ }
71
+ if (options.claimValidators !== undefined) {
72
+ for (const [claim, validator] of Object.entries(options.claimValidators)) {
73
+ if (typeof validator !== "function") {
74
+ throw new TypeError(`Claim validator for "${claim}" must be a function`);
75
+ }
76
+ }
77
+ }
78
+ if (options.subject !== undefined) {
79
+ requireNonEmptyString(options.subject, "subject");
80
+ }
81
+ const profile = {
82
+ typ,
83
+ iss,
84
+ aud,
85
+ alg,
86
+ keys: normalizeKeys(options.keys, options.algorithms),
87
+ maxTokenAge: toSeconds(maxTokenAge),
88
+ maxClockSkew: toSeconds(maxClockSkew),
89
+ };
90
+ if (options.revocation !== undefined)
91
+ profile.revocation = options.revocation;
92
+ if (options.claimValidators !== undefined) {
93
+ profile.claimValidators = { ...options.claimValidators };
94
+ }
95
+ if (options.subject !== undefined)
96
+ profile.subject = options.subject;
97
+ if (options.unsafeFailOpenOnRevocationError === true) {
98
+ profile.unsafeFailOpenOnRevocationError = true;
99
+ }
100
+ return Object.freeze(profile);
101
+ }
102
+ //# sourceMappingURL=profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../../../src/jwt/profile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * The sign builder.
3
+ *
4
+ * `.sign()` refuses to produce a token unless `typ` (constructor), `iss`,
5
+ * `aud` and `exp` are set - each requirement individually waivable only
6
+ * via a grep-loud `unsafeAllowMissing*` call. Every token gets a unique
7
+ * `jti`, lifetimes are capped, and the payload hygiene scanner runs as
8
+ * the final step before signing.
9
+ */
10
+ import { CompactSign } from "jose";
11
+ import { KeyTypeMismatch, MaxLifetimeExceeded, MissingClaim, } from "../util/errors.js";
12
+ import { parseDuration } from "../lib/duration.js";
13
+ import { encodeUTF8 } from "../lib/utf8.js";
14
+ import { scanPayloadForSensitiveData } from "../lib/payload_hygiene.js";
15
+ import { isLacewingKey } from "../types.js";
16
+ const DEFAULT_MAX_LIFETIME_SECONDS = 3600;
17
+ // Set through dedicated methods only, so they can't be smuggled past the
18
+ // requirement checks via .claim().
19
+ const RESERVED_CLAIMS = new Set(["iss", "sub", "aud", "exp", "nbf", "iat", "jti"]);
20
+ /**
21
+ * Fluent builder for a signed JWT. `typ` is a constructor argument, and
22
+ * `.sign()` refuses to run without `issuer`, `audience` and `expiresIn`
23
+ * (each waivable only via a grep-loud `unsafeAllowMissing*` call).
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const token = await new SignJWT("at+jwt")
28
+ * .issuer("https://auth.example.com")
29
+ * .audience("https://api.example.com")
30
+ * .subject("user-42")
31
+ * .claim("scope", "read")
32
+ * .expiresIn("10m")
33
+ * .sign(privateKey);
34
+ * ```
35
+ */
36
+ export class SignJWT {
37
+ #typ;
38
+ #maxLifetime;
39
+ #claims = new Map();
40
+ #allowedClaims = new Set();
41
+ #iss;
42
+ #aud;
43
+ #sub;
44
+ #jti;
45
+ #expiresIn;
46
+ #notBefore;
47
+ #waiveIssuer = false;
48
+ #waiveAudience = false;
49
+ #waiveExpiration = false;
50
+ /** Explicit typing is mandatory (§3.11): the `typ` is a constructor argument. */
51
+ constructor(typ, options = {}) {
52
+ if (typeof typ !== "string" || typ.length === 0) {
53
+ throw new TypeError("SignJWT requires an explicit token typ, e.g. new SignJWT(\"at+jwt\")");
54
+ }
55
+ this.#typ = typ;
56
+ this.#maxLifetime = parseDuration(options.maxLifetime ?? DEFAULT_MAX_LIFETIME_SECONDS);
57
+ }
58
+ issuer(iss) {
59
+ if (typeof iss !== "string" || iss.length === 0) {
60
+ throw new TypeError("issuer must be a non-empty string");
61
+ }
62
+ this.#iss = iss;
63
+ return this;
64
+ }
65
+ audience(aud) {
66
+ const values = Array.isArray(aud) ? aud : [aud];
67
+ if (values.length === 0 || values.some((v) => typeof v !== "string" || v.length === 0)) {
68
+ throw new TypeError("audience must be a non-empty string or array of them");
69
+ }
70
+ this.#aud = aud;
71
+ return this;
72
+ }
73
+ subject(sub) {
74
+ if (typeof sub !== "string" || sub.length === 0) {
75
+ throw new TypeError("subject must be a non-empty string");
76
+ }
77
+ this.#sub = sub;
78
+ return this;
79
+ }
80
+ /** Override the auto-assigned `jti`. Uniqueness is then your problem. */
81
+ jwtId(jti) {
82
+ if (typeof jti !== "string" || jti.length === 0) {
83
+ throw new TypeError("jwtId must be a non-empty string");
84
+ }
85
+ this.#jti = jti;
86
+ return this;
87
+ }
88
+ /** Token lifetime from now, e.g. `"10m"` or `600`. Capped by maxLifetime. */
89
+ expiresIn(duration) {
90
+ const seconds = parseDuration(duration);
91
+ if (seconds < 1) {
92
+ throw new TypeError("expiresIn must be at least one second");
93
+ }
94
+ this.#expiresIn = seconds;
95
+ return this;
96
+ }
97
+ /** Delay validity by `duration` from now (`nbf`). */
98
+ notBefore(duration) {
99
+ this.#notBefore = parseDuration(duration);
100
+ return this;
101
+ }
102
+ /** Set a custom claim. Registered claims must use their dedicated methods. */
103
+ claim(name, value) {
104
+ if (typeof name !== "string" || name.length === 0) {
105
+ throw new TypeError("claim name must be a non-empty string");
106
+ }
107
+ if (RESERVED_CLAIMS.has(name)) {
108
+ throw new TypeError(`"${name}" is a registered claim - use the dedicated builder method`);
109
+ }
110
+ this.#claims.set(name, value);
111
+ return this;
112
+ }
113
+ /** Waive the payload hygiene scanner for one claim (LW-payload). Grep for this in review. */
114
+ unsafeAllowClaim(name) {
115
+ this.#allowedClaims.add(name);
116
+ return this;
117
+ }
118
+ /** Waive the mandatory `iss`. Grep for this in review. */
119
+ unsafeAllowMissingIssuer() {
120
+ this.#waiveIssuer = true;
121
+ return this;
122
+ }
123
+ /** Waive the mandatory `aud`. Grep for this in review. */
124
+ unsafeAllowMissingAudience() {
125
+ this.#waiveAudience = true;
126
+ return this;
127
+ }
128
+ /** Waive the mandatory `exp`. Grep for this in review. */
129
+ unsafeAllowMissingExpiration() {
130
+ this.#waiveExpiration = true;
131
+ return this;
132
+ }
133
+ async sign(key) {
134
+ if (!isLacewingKey(key)) {
135
+ throw new TypeError("sign() only accepts keys imported through Lacewing");
136
+ }
137
+ if (key.keyType === "public") {
138
+ throw new KeyTypeMismatch("Cannot sign with a public key");
139
+ }
140
+ if (this.#iss === undefined && !this.#waiveIssuer) {
141
+ throw new MissingClaim("iss", "Tokens must name their issuer - call .issuer() (or, deliberately, .unsafeAllowMissingIssuer())");
142
+ }
143
+ if (this.#aud === undefined && !this.#waiveAudience) {
144
+ throw new MissingClaim("aud", "Tokens must name their audience - call .audience() (or, deliberately, .unsafeAllowMissingAudience())");
145
+ }
146
+ if (this.#expiresIn === undefined && !this.#waiveExpiration) {
147
+ throw new MissingClaim("exp", "Tokens must expire - call .expiresIn() (or, deliberately, .unsafeAllowMissingExpiration())");
148
+ }
149
+ if (this.#expiresIn !== undefined && this.#expiresIn > this.#maxLifetime) {
150
+ throw new MaxLifetimeExceeded(`Requested lifetime exceeds the ${this.#maxLifetime}s cap - ` +
151
+ "long-lived tokens need an explicit maxLifetime option");
152
+ }
153
+ const now = Math.floor(Date.now() / 1000);
154
+ const payload = Object.fromEntries(this.#claims);
155
+ if (this.#iss !== undefined)
156
+ payload.iss = this.#iss;
157
+ if (this.#sub !== undefined)
158
+ payload.sub = this.#sub;
159
+ if (this.#aud !== undefined)
160
+ payload.aud = this.#aud;
161
+ payload.jti = this.#jti ?? globalThis.crypto.randomUUID();
162
+ if (this.#notBefore !== undefined)
163
+ payload.nbf = now + this.#notBefore;
164
+ if (this.#expiresIn !== undefined)
165
+ payload.exp = now + this.#expiresIn;
166
+ payload.iat = now;
167
+ scanPayloadForSensitiveData(payload, this.#allowedClaims);
168
+ return new CompactSign(encodeUTF8(JSON.stringify(payload)))
169
+ .setProtectedHeader({ alg: key.algorithm, typ: this.#typ })
170
+ .sign(key.key);
171
+ }
172
+ }
173
+ //# sourceMappingURL=sign.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign.js","sourceRoot":"","sources":["../../../src/jwt/sign.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * The one and only verification path (RFC 8725 §3.3).
3
+ *
4
+ * Order of operations, fail-fast, all-or-nothing:
5
+ * 1. structural parse (length cap, strict base64url, strict UTF-8)
6
+ * 2. header validation (allowlist, typ, kid hygiene, forbidden params)
7
+ * 3. key resolution from the profile's key source
8
+ * 4. signature verification
9
+ * 5. claims validation
10
+ * 6. custom claim validators
11
+ * 7. revocation check - last, so unauthenticated input can never
12
+ * drive store lookups (LW-rev.3)
13
+ *
14
+ * There is no partial result and no decoded-but-unverified escape hatch
15
+ * here; that lives, loudly branded, in `util/unsafe-decode.ts`.
16
+ */
17
+ import { compactVerify } from "jose";
18
+ import { AlgorithmNotAllowed, JWTInvalid, JWTRevoked, MissingClaim, RevocationCheckFailed, } from "../util/errors.js";
19
+ import { decodeBase64url } from "../lib/base64url.js";
20
+ import { decodeUTF8 } from "../lib/utf8.js";
21
+ import { parseJsonObject } from "../lib/json.js";
22
+ import { validateHeader } from "../lib/headers.js";
23
+ import { validateClaims } from "../lib/claims.js";
24
+ import { buildRevocationContext } from "../revocation/store.js";
25
+ import { isLacewingKey, } from "../types.js";
26
+ // Bounded before any parsing so garbage can't allocate unboundedly.
27
+ const MAX_TOKEN_LENGTH = 16384;
28
+ function parseSegmentJson(bytes, what) {
29
+ return parseJsonObject(decodeUTF8(bytes), what);
30
+ }
31
+ async function resolveKey(profile, header) {
32
+ if (isLacewingKey(profile.keys)) {
33
+ if (profile.keys.algorithm !== header.alg) {
34
+ throw new AlgorithmNotAllowed("Token algorithm does not match the profile's key");
35
+ }
36
+ return { alg: header.alg, key: profile.keys.key };
37
+ }
38
+ return profile.keys.getVerificationKey(header, profile.alg);
39
+ }
40
+ /**
41
+ * Verify a token against a profile. The returned {@link VerifiedJwt} is
42
+ * the only way to obtain one - there is no backdoor.
43
+ *
44
+ * On any failure it throws a typed error ({@link JWTExpired},
45
+ * {@link AlgorithmNotAllowed}, {@link JWTClaimValidationFailed}, ...) and yields
46
+ * no partial result. There is no `decode()` and no `ignoreExpiration`.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * const profile = defineProfile({
51
+ * typ: "at+jwt",
52
+ * issuer: "https://auth.example.com",
53
+ * audience: "https://api.example.com",
54
+ * algorithms: ["EdDSA"],
55
+ * keys: createRemoteJWKSet("https://auth.example.com/jwks"),
56
+ * maxTokenAge: "10m",
57
+ * });
58
+ *
59
+ * const { payload } = await jwtVerify(token, profile); // every check passed
60
+ * ```
61
+ */
62
+ export async function jwtVerify(token, profile) {
63
+ if (typeof token !== "string" || token.length === 0) {
64
+ throw new JWTInvalid("Token must be a non-empty string");
65
+ }
66
+ if (token.length > MAX_TOKEN_LENGTH) {
67
+ throw new JWTInvalid("Token exceeds the maximum length");
68
+ }
69
+ const segments = token.split(".");
70
+ if (segments.length !== 3) {
71
+ throw new JWTInvalid("Token must have exactly three segments");
72
+ }
73
+ const [rawHeader, rawPayload, rawSignature] = segments;
74
+ if (rawHeader === "" || rawPayload === "" || rawSignature === "") {
75
+ throw new JWTInvalid("Token has an empty segment");
76
+ }
77
+ // Strict decoding is authoritative: Lacewing's canonical base64url and
78
+ // fatal UTF-8 run before jose ever sees the token, closing parser
79
+ // differentials (§3.7 and the strictness attack vectors).
80
+ const header = validateHeader(parseSegmentJson(decodeBase64url(rawHeader), "header"), profile);
81
+ const payloadBytes = decodeBase64url(rawPayload);
82
+ decodeBase64url(rawSignature);
83
+ const resolved = await resolveKey(profile, header);
84
+ try {
85
+ await compactVerify(token, resolved.key, {
86
+ algorithms: [header.alg],
87
+ });
88
+ }
89
+ catch (cause) {
90
+ throw new JWTInvalid("Token signature verification failed", { cause });
91
+ }
92
+ const payload = parseSegmentJson(payloadBytes, "payload");
93
+ await validateClaims(payload, profile);
94
+ // Revocation last (LW-rev.3): only signed, claims-valid tokens ever
95
+ // reach the store, so forged input can't probe or flood it.
96
+ if (profile.revocation !== undefined) {
97
+ if (typeof payload.jti !== "string") {
98
+ throw new MissingClaim("jti", "This profile has a revocation store but the token carries no jti");
99
+ }
100
+ let revoked;
101
+ try {
102
+ revoked = await profile.revocation.isRevoked(buildRevocationContext(payload));
103
+ }
104
+ catch (cause) {
105
+ if (profile.unsafeFailOpenOnRevocationError === true) {
106
+ revoked = false;
107
+ }
108
+ else {
109
+ throw new RevocationCheckFailed("Revocation store errored - failing closed (LW-rev.4)", { cause });
110
+ }
111
+ }
112
+ if (revoked) {
113
+ throw new JWTRevoked("Token has been revoked");
114
+ }
115
+ }
116
+ return { header, payload: payload };
117
+ }
118
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../src/jwt/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Encryption key import/generation (the JWE counterpart of `key/import.ts` and
3
+ * `key/generate.ts`). Every encryption key enters here and leaves bound to
4
+ * exactly one key-management algorithm, carried in the type. `EncryptJWT` and
5
+ * `jwtDecrypt` never accept a bare `CryptoKey`, so the binding cannot be
6
+ * bypassed - and a signing key can never be used to encrypt (different brand).
7
+ */
8
+ import { generateKeyPair as joseGenerateKeyPair, importJWK, importPKCS8, importSPKI } from "jose";
9
+ import { KeyImportFailed, KeyTypeMismatch } from "../util/errors.js";
10
+ import { getContentEncryptionProperties, getKeyManagementProperties, } from "../lib/jwe_algorithms.js";
11
+ import { decodeBase64url } from "../lib/base64url.js";
12
+ import { createLacewingEncryptionKey, SetAlg, } from "../types.js";
13
+ function assertSymmetric(info, algorithm) {
14
+ if (info.kind !== "aeskw") {
15
+ throw new KeyTypeMismatch(`${algorithm} is not an AES key-wrapping algorithm - use ` +
16
+ (info.kind === "dir" ? "generateDirectKey(enc)" : "generateEncryptionKeyPair()"));
17
+ }
18
+ }
19
+ /**
20
+ * Generate an asymmetric encryption key pair for `algorithm` (ECDH-ES* or
21
+ * RSA-OAEP-256). The recipient keeps the private key; senders encrypt to the
22
+ * public key.
23
+ */
24
+ export async function generateEncryptionKeyPair(algorithm, options = {}) {
25
+ const info = getKeyManagementProperties(algorithm);
26
+ if (info.kind !== "ecdh" && info.kind !== "rsa") {
27
+ throw new KeyTypeMismatch(`${algorithm} is symmetric - use generateEncryptionSecret()/generateDirectKey()`);
28
+ }
29
+ const alg = SetAlg(algorithm);
30
+ try {
31
+ const { publicKey, privateKey } = await joseGenerateKeyPair(algorithm, {
32
+ extractable: options.extractable ?? false,
33
+ });
34
+ return {
35
+ publicKey: createLacewingEncryptionKey(alg, "public", publicKey),
36
+ privateKey: createLacewingEncryptionKey(alg, "private", privateKey),
37
+ };
38
+ }
39
+ catch (cause) {
40
+ throw new KeyImportFailed("Encryption key generation failed", { cause });
41
+ }
42
+ }
43
+ /** Generate a random symmetric key for an AES key-wrapping algorithm (A*KW / A*GCMKW). */
44
+ export function generateEncryptionSecret(algorithm) {
45
+ const info = getKeyManagementProperties(algorithm);
46
+ assertSymmetric(info, algorithm);
47
+ const alg = SetAlg(algorithm);
48
+ const secret = new Uint8Array(info.secretBytes);
49
+ globalThis.crypto.getRandomValues(secret);
50
+ return createLacewingEncryptionKey(alg, "secret", secret);
51
+ }
52
+ /**
53
+ * Generate a random direct (`alg: "dir"`) key sized to a content-encryption
54
+ * algorithm. The key *is* the content-encryption key, so it is inseparable
55
+ * from its `enc`: a 32-byte key is for A256GCM/A128CBC-HS256, and so on.
56
+ */
57
+ export function generateDirectKey(enc) {
58
+ const info = getContentEncryptionProperties(enc);
59
+ const alg = SetAlg("dir");
60
+ const secret = new Uint8Array(info.cekBytes);
61
+ globalThis.crypto.getRandomValues(secret);
62
+ return createLacewingEncryptionKey(alg, "secret", secret);
63
+ }
64
+ function importSymmetric(material, info, algorithm) {
65
+ let secret;
66
+ if (material instanceof Uint8Array) {
67
+ secret = material;
68
+ }
69
+ else if (typeof material === "object" &&
70
+ material !== null &&
71
+ !(material instanceof CryptoKey) &&
72
+ material.kty === "oct" &&
73
+ typeof material.k === "string") {
74
+ secret = decodeBase64url(material.k);
75
+ }
76
+ else {
77
+ throw new KeyImportFailed(`${algorithm} keys must be a Uint8Array or oct JWK`);
78
+ }
79
+ // AES key-wrap keys are a fixed size; `dir` keys must match some valid CEK size.
80
+ if (info.kind === "aeskw" && secret.length !== info.secretBytes) {
81
+ throw new KeyTypeMismatch(`${algorithm} requires a ${info.secretBytes}-byte key`);
82
+ }
83
+ if (info.kind === "dir" && ![16, 24, 32, 48, 64].includes(secret.length)) {
84
+ throw new KeyTypeMismatch("A dir key must be 16, 24, 32, 48 or 64 bytes (a valid CEK size)");
85
+ }
86
+ return secret;
87
+ }
88
+ async function importAsymmetricEncryption(material, algorithm) {
89
+ if (material instanceof CryptoKey) {
90
+ if (material.type !== "public" && material.type !== "private") {
91
+ throw new KeyTypeMismatch(`A secret key cannot be used with ${algorithm}`);
92
+ }
93
+ return { key: material, keyType: material.type };
94
+ }
95
+ if (typeof material === "string") {
96
+ if (material.includes("-----BEGIN PRIVATE KEY-----")) {
97
+ return { key: await importPKCS8(material, algorithm), keyType: "private" };
98
+ }
99
+ if (material.includes("-----BEGIN PUBLIC KEY-----")) {
100
+ return { key: await importSPKI(material, algorithm), keyType: "public" };
101
+ }
102
+ throw new KeyImportFailed("Unsupported PEM - only PKCS#8 private and SPKI public keys are accepted");
103
+ }
104
+ if (typeof material === "object" && material !== null) {
105
+ const jwk = material;
106
+ const keyType = typeof jwk.d === "string" ? "private" : "public";
107
+ return { key: await importJWK(jwk, algorithm), keyType };
108
+ }
109
+ throw new KeyImportFailed("Unsupported encryption key material");
110
+ }
111
+ /**
112
+ * Import encryption key material and bind it to `algorithm`. Throws
113
+ * {@link KeyTypeMismatch} when material and algorithm disagree, and
114
+ * {@link KeyImportFailed} for anything else.
115
+ */
116
+ export async function importEncryptionKey(material, algorithm) {
117
+ const info = getKeyManagementProperties(algorithm);
118
+ const alg = SetAlg(algorithm);
119
+ try {
120
+ if (info.kty === "oct") {
121
+ return createLacewingEncryptionKey(alg, "secret", importSymmetric(material, info, algorithm));
122
+ }
123
+ const { key, keyType } = await importAsymmetricEncryption(material, algorithm);
124
+ return createLacewingEncryptionKey(alg, keyType, key);
125
+ }
126
+ catch (cause) {
127
+ if (cause instanceof KeyTypeMismatch || cause instanceof KeyImportFailed)
128
+ throw cause;
129
+ throw new KeyImportFailed("Encryption key import failed", { cause });
130
+ }
131
+ }
132
+ //# sourceMappingURL=encryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.js","sourceRoot":"","sources":["../../../src/key/encryption.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Key export to JWK / PEM. Only works on extractable keys - keys from
3
+ * `generateKeyPair` are non-extractable unless you asked otherwise.
4
+ */
5
+ import { exportJWK, exportPKCS8, exportSPKI } from "jose";
6
+ import { KeyExportFailed } from "../util/errors.js";
7
+ import { encodeBase64url } from "../lib/base64url.js";
8
+ /** Export a key as a JWK, with its bound `alg` and `use: "sig"` set. */
9
+ export async function exportKeyJWK(key) {
10
+ try {
11
+ if (key.keyType === "secret") {
12
+ return {
13
+ kty: "oct",
14
+ k: encodeBase64url(key.key),
15
+ alg: key.algorithm,
16
+ use: "sig",
17
+ };
18
+ }
19
+ const jwk = await exportJWK(key.key);
20
+ return { ...jwk, alg: key.algorithm, use: "sig" };
21
+ }
22
+ catch (cause) {
23
+ if (cause instanceof KeyExportFailed)
24
+ throw cause;
25
+ throw new KeyExportFailed("Key export failed - is the key extractable?", {
26
+ cause,
27
+ });
28
+ }
29
+ }
30
+ /** Export an asymmetric key as PEM (PKCS#8 for private, SPKI for public). */
31
+ export async function exportKeyPEM(key) {
32
+ if (key.keyType === "secret") {
33
+ throw new KeyExportFailed("Symmetric secrets have no PEM representation");
34
+ }
35
+ try {
36
+ return key.keyType === "private"
37
+ ? await exportPKCS8(key.key)
38
+ : await exportSPKI(key.key);
39
+ }
40
+ catch (cause) {
41
+ throw new KeyExportFailed("Key export failed - is the key extractable?", {
42
+ cause,
43
+ });
44
+ }
45
+ }
46
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../../src/key/export.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGtD,wEAAwE;AACxE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAgB;IAClD,IAAI,CAAC;QACJ,IAAI,GAAG,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO;gBACN,GAAG,EAAE,KAAK;gBACV,CAAC,EAAE,eAAe,CAAC,GAAG,CAAC,GAAiB,CAAC;gBACzC,GAAG,EAAE,GAAG,CAAC,SAAS;gBAClB,GAAG,EAAE,KAAK;aACV,CAAC;QACH,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,GAAgB,CAAC,CAAC;QAClD,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,EAAe,CAAC;IAChE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,KAAK,YAAY,eAAe;YAAE,MAAM,KAAK,CAAC;QAClD,MAAM,IAAI,eAAe,CAAC,6CAA6C,EAAE;YACxE,KAAK;SACL,CAAC,CAAC;IACJ,CAAC;AACF,CAAC;AAED,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAgB;IAClD,IAAI,GAAG,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,eAAe,CAAC,8CAA8C,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,CAAC;QACJ,OAAO,GAAG,CAAC,OAAO,KAAK,SAAS;YAC/B,CAAC,CAAC,MAAM,WAAW,CAAC,GAAG,CAAC,GAAgB,CAAC;YACzC,CAAC,CAAC,MAAM,UAAU,CAAC,GAAG,CAAC,GAAgB,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,eAAe,CAAC,6CAA6C,EAAE;YACxE,KAAK;SACL,CAAC,CAAC;IACJ,CAAC;AACF,CAAC"}