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,196 @@
1
+ /**
2
+ * A string that has been validated against the algorithm registry.
3
+ * `"none"` is unrepresentable (RFC 8725 §3.2).
4
+ */
5
+ export type ValidAlg = string & {
6
+ readonly __alg: unique symbol;
7
+ };
8
+ /**
9
+ * Brand a string as a {@link ValidAlg}. Rejects `"none"` in any casing.
10
+ * Registry membership is enforced separately by `lib/algorithms.ts`;
11
+ * this brand only guarantees the value is not the `none` algorithm.
12
+ */
13
+ export declare const SetAlg: (value: string) => ValidAlg;
14
+ /**
15
+ * Seconds, branded so raw numbers must pass through {@link toSeconds}
16
+ * (or `parseDuration`) before being used as a duration.
17
+ */
18
+ export type DurationSeconds = number & {
19
+ readonly __duration: unique symbol;
20
+ };
21
+ export declare function toSeconds(value: number): DurationSeconds;
22
+ export interface JwtHeader {
23
+ alg: ValidAlg;
24
+ typ: string;
25
+ cty?: string;
26
+ kid?: string;
27
+ }
28
+ export interface JwtPayLoad {
29
+ iss: string;
30
+ sub?: string;
31
+ aud: string | string[];
32
+ jti?: string;
33
+ nbf?: number;
34
+ exp: number;
35
+ iat: number;
36
+ [propName: string]: unknown;
37
+ }
38
+ /** @internal Shared shape behind {@link VerifiedJwt} and {@link UntrustedJwt}. */
39
+ type JwtShape = {
40
+ header: JwtHeader;
41
+ payload: JwtPayLoad;
42
+ };
43
+ /** Only ever produced by `jwtVerify` - proof that every check passed. */
44
+ export type VerifiedJwt = JwtShape & {
45
+ readonly __brand: "VerifiedJwt";
46
+ };
47
+ /** Produced by `unsafeDecode` - type-incompatible with {@link VerifiedJwt}. */
48
+ export type UntrustedJwt = JwtShape & {
49
+ readonly __brand: "UntrustedJwt";
50
+ };
51
+ declare const BrandSymbol: unique symbol;
52
+ export type Branded<T, BrandName extends string> = T & {
53
+ readonly [BrandSymbol]: BrandName;
54
+ };
55
+ /**
56
+ * A key bound to exactly one algorithm at import time.
57
+ * The algorithm travels in the type parameter, so a `LacewingKey<"ES256">`
58
+ * cannot be passed where a `LacewingKey<"HS256">` is expected.
59
+ */
60
+ export type LacewingKey<Alg extends string = string> = {
61
+ readonly __brand: "LacewingKey";
62
+ readonly algorithm: Alg & ValidAlg;
63
+ readonly keyType: "public" | "private" | "secret";
64
+ /** The underlying CryptoKey / raw secret. Internal - do not touch. */
65
+ readonly key: unknown;
66
+ };
67
+ /** Internal constructor - use `importKey` / `generateKeyPair` instead. */
68
+ export declare function createLacewingKey<const Alg extends string>(algorithm: Alg & ValidAlg, keyType: "public" | "private" | "secret", key: unknown): LacewingKey<Alg>;
69
+ export declare function isLacewingKey(value: unknown): value is LacewingKey;
70
+ export type StaticJWK = {
71
+ kty: "RSA" | "EC" | "OKP" | "oct";
72
+ use?: "sig" | "enc";
73
+ alg?: string;
74
+ kid?: string;
75
+ [key: string]: unknown;
76
+ };
77
+ export type StaticJWKS = {
78
+ keys: StaticJWK[];
79
+ };
80
+ export type RemoteJWKS = {
81
+ jwksUri: string;
82
+ cacheTtlSeconds?: number;
83
+ cooldownSeconds?: number;
84
+ timeoutMs?: number;
85
+ };
86
+ export type JWKSConfig = StaticJWKS | RemoteJWKS;
87
+ /** A key resolved by a {@link KeySource} for one specific token. */
88
+ export interface ResolvedVerificationKey {
89
+ alg: ValidAlg;
90
+ key: unknown;
91
+ }
92
+ /**
93
+ * Anything that can produce a verification key for a token header.
94
+ * Implemented by `createLocalJWKSet` and `createRemoteJWKSet`.
95
+ */
96
+ export interface KeySource {
97
+ getVerificationKey(header: JwtHeader, allowedAlgorithms: readonly ValidAlg[]): Promise<ResolvedVerificationKey>;
98
+ }
99
+ export interface TokenRevocationContext {
100
+ jti?: string;
101
+ sub?: string;
102
+ sid?: string;
103
+ exp: number;
104
+ iat: number;
105
+ }
106
+ export interface RevocationStore {
107
+ isRevoked(context: TokenRevocationContext): Promise<boolean>;
108
+ isAnyRevoked?(contexts: TokenRevocationContext[]): Promise<boolean[]>;
109
+ }
110
+ export type ValidateClaim = (claimValue: unknown, fullPayload: Record<string, unknown>) => void | Promise<void>;
111
+ /**
112
+ * The claim-checking slice shared by the verify (JWS) and decrypt (JWE) paths.
113
+ * Both {@link ExpectedJwtProfile} and {@link ExpectedDecryptionProfile}
114
+ * satisfy it, so one claims engine serves both.
115
+ */
116
+ export interface ClaimsPolicy {
117
+ iss: string;
118
+ aud: string;
119
+ maxTokenAge: DurationSeconds;
120
+ maxClockSkew: DurationSeconds;
121
+ subject?: string;
122
+ claimValidators?: Record<string, ValidateClaim>;
123
+ }
124
+ /**
125
+ * A key bound to exactly one JWE key-management algorithm at import time - the
126
+ * encryption counterpart of {@link LacewingKey}. Kept a distinct brand so an
127
+ * encryption key can never be handed to `SignJWT.sign`, nor a signing key to
128
+ * `EncryptJWT.encrypt`.
129
+ */
130
+ export type LacewingEncryptionKey<Alg extends string = string> = {
131
+ readonly __brand: "LacewingEncryptionKey";
132
+ readonly algorithm: Alg & ValidAlg;
133
+ readonly keyType: "public" | "private" | "secret";
134
+ readonly key: unknown;
135
+ };
136
+ /** Internal constructor - use `importEncryptionKey` / `generateEncryptionKeyPair`. */
137
+ export declare function createLacewingEncryptionKey<const Alg extends string>(algorithm: Alg & ValidAlg, keyType: "public" | "private" | "secret", key: unknown): LacewingEncryptionKey<Alg>;
138
+ export declare function isLacewingEncryptionKey(value: unknown): value is LacewingEncryptionKey;
139
+ /** A decrypted JWE's protected header (adds `enc` to the JWS header shape). */
140
+ export interface JweHeader {
141
+ alg: ValidAlg;
142
+ enc: ValidAlg;
143
+ typ: string;
144
+ cty?: string;
145
+ kid?: string;
146
+ }
147
+ /**
148
+ * Only ever produced by `jwtDecrypt`: proof that a token decrypted (and thus
149
+ * authenticated by its AEAD) and passed every claim check. A distinct brand
150
+ * from {@link VerifiedJwt} - the two are not interchangeable.
151
+ */
152
+ export type DecryptedJwt = {
153
+ header: JweHeader;
154
+ payload: JwtPayLoad;
155
+ } & {
156
+ readonly __brand: "DecryptedJwt";
157
+ };
158
+ /**
159
+ * The security boundary for decryption - the JWE analogue of
160
+ * {@link ExpectedJwtProfile}. Built by `defineDecryptionProfile`, the only
161
+ * argument shape `jwtDecrypt` accepts.
162
+ */
163
+ export interface ExpectedDecryptionProfile extends ClaimsPolicy {
164
+ typ: string;
165
+ /** Allowlist of key-management (`alg`) algorithms; the header never decides. */
166
+ keyManagementAlgorithms: readonly ValidAlg[];
167
+ /** Allowlist of content-encryption (`enc`) algorithms. */
168
+ contentEncryptionAlgorithms: readonly ValidAlg[];
169
+ /** The private/secret key that decrypts (scoped to this profile's issuer). */
170
+ key: LacewingEncryptionKey;
171
+ revocation?: RevocationStore;
172
+ unsafeFailOpenOnRevocationError?: boolean;
173
+ }
174
+ /**
175
+ * The security boundary for verification (RFC 8725 §3.12).
176
+ * Built by `defineProfile` - the only argument shape `jwtVerify` accepts.
177
+ */
178
+ export interface ExpectedJwtProfile {
179
+ typ: string;
180
+ iss: string;
181
+ aud: string;
182
+ alg: readonly ValidAlg[];
183
+ keys: KeySource | LacewingKey;
184
+ maxTokenAge: DurationSeconds;
185
+ maxClockSkew: DurationSeconds;
186
+ revocation?: RevocationStore;
187
+ claimValidators?: Record<string, ValidateClaim>;
188
+ subject?: string;
189
+ /**
190
+ * Deliberately ugly escape hatch: when the revocation store errors,
191
+ * accept the token anyway instead of failing closed (LW-rev.4).
192
+ */
193
+ unsafeFailOpenOnRevocationError?: boolean;
194
+ }
195
+ export {};
196
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Typed error hierarchy.
3
+ *
4
+ * Every error carries a machine-readable `code` so operators can branch on
5
+ * failure modes, while messages stay generic: security-relevant rejections
6
+ * never echo untrusted token content (no oracle for attackers, no log
7
+ * injection - RFC 8725 §3.10 hygiene).
8
+ */
9
+ export declare abstract class JWTError extends Error {
10
+ abstract readonly code: string;
11
+ constructor(message: string, options?: {
12
+ cause?: unknown;
13
+ });
14
+ }
15
+ /** Token structure or signature is invalid. */
16
+ export declare class JWTInvalid extends JWTError {
17
+ readonly code = "JWT_INVALID";
18
+ }
19
+ /** Token is past `exp`, or older than the profile's `maxTokenAge`. */
20
+ export declare class JWTExpired extends JWTError {
21
+ readonly code = "JWT_EXPIRED";
22
+ }
23
+ /** A claim is present but does not satisfy the profile's rules. */
24
+ export declare class JWTClaimValidationFailed extends JWTError {
25
+ readonly code = "JWT_CLAIM_VALIDATION_FAILED";
26
+ /** Name of the offending claim (never its value). */
27
+ readonly claim: string;
28
+ constructor(claim: string, message: string, options?: {
29
+ cause?: unknown;
30
+ });
31
+ }
32
+ /** A claim required by the profile or by Lacewing policy is absent. */
33
+ export declare class MissingClaim extends JWTError {
34
+ readonly code = "MISSING_CLAIM";
35
+ readonly claim: string;
36
+ constructor(claim: string, message?: string);
37
+ }
38
+ /** Algorithm is not in the registry / profile allowlist. */
39
+ export declare class AlgorithmNotAllowed extends JWTError {
40
+ readonly code = "ALGORITHM_NOT_ALLOWED";
41
+ }
42
+ /** Key material could not be imported. */
43
+ export declare class KeyImportFailed extends JWTError {
44
+ readonly code = "KEY_IMPORT_FAILED";
45
+ }
46
+ /** Key does not match the algorithm it is being used with. */
47
+ export declare class KeyTypeMismatch extends JWTError {
48
+ readonly code = "KEY_TYPE_MISMATCH";
49
+ }
50
+ /** Key material could not be exported. */
51
+ export declare class KeyExportFailed extends JWTError {
52
+ readonly code = "KEY_EXPORT_FAILED";
53
+ }
54
+ /** HMAC secret failed the strength checks (RFC 8725 §3.5). */
55
+ export declare class EntropyCheckFailed extends JWTError {
56
+ readonly code = "ENTROPY_CHECK_FAILED";
57
+ }
58
+ /** Remote JWKS could not be fetched or parsed. */
59
+ export declare class JWKSFetchFailed extends JWTError {
60
+ readonly code = "JWKS_FETCH_FAILED";
61
+ }
62
+ /** No key in the JWKS matches the token's header. */
63
+ export declare class JWKSNoMatchingKey extends JWTError {
64
+ readonly code = "JWKS_NO_MATCHING_KEY";
65
+ }
66
+ /** Token is valid but its `jti` has been revoked (LW-rev.2). */
67
+ export declare class JWTRevoked extends JWTError {
68
+ readonly code = "JWT_REVOKED";
69
+ }
70
+ /** The revocation store errored; Lacewing fails closed (LW-rev.4). */
71
+ export declare class RevocationCheckFailed extends JWTError {
72
+ readonly code = "REVOCATION_CHECK_FAILED";
73
+ }
74
+ /** Sign-time payload hygiene scanner found sensitive data (LW-payload). */
75
+ export declare class PayloadHygieneViolation extends JWTError {
76
+ readonly code = "PAYLOAD_HYGIENE_VIOLATION";
77
+ /** Name of the offending claim (never its value). */
78
+ readonly claim: string;
79
+ constructor(claim: string, message: string);
80
+ }
81
+ /** Requested token lifetime exceeds the configured cap (LW-life.1). */
82
+ export declare class MaxLifetimeExceeded extends JWTError {
83
+ readonly code = "MAX_LIFETIME_EXCEEDED";
84
+ }
85
+ /** `Authorization` header failed strict RFC 6750 parsing (LW-http.2). */
86
+ export declare class BearerParseFailed extends JWTError {
87
+ readonly code = "BEARER_PARSE_FAILED";
88
+ }
89
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../../src/util/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,8BAAsB,QAAS,SAAQ,KAAK;IAC3C,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEnB,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAI1D;AAED,+CAA+C;AAC/C,qBAAa,UAAW,SAAQ,QAAQ;IACvC,QAAQ,CAAC,IAAI,iBAAiB;CAC9B;AAED,sEAAsE;AACtE,qBAAa,UAAW,SAAQ,QAAQ;IACvC,QAAQ,CAAC,IAAI,iBAAiB;CAC9B;AAED,mEAAmE;AACnE,qBAAa,wBAAyB,SAAQ,QAAQ;IACrD,QAAQ,CAAC,IAAI,iCAAiC;IAC9C,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAIzE;AAED,uEAAuE;AACvE,qBAAa,YAAa,SAAQ,QAAQ;IACzC,QAAQ,CAAC,IAAI,mBAAmB;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAI3C;AAED,4DAA4D;AAC5D,qBAAa,mBAAoB,SAAQ,QAAQ;IAChD,QAAQ,CAAC,IAAI,2BAA2B;CACxC;AAED,0CAA0C;AAC1C,qBAAa,eAAgB,SAAQ,QAAQ;IAC5C,QAAQ,CAAC,IAAI,uBAAuB;CACpC;AAED,8DAA8D;AAC9D,qBAAa,eAAgB,SAAQ,QAAQ;IAC5C,QAAQ,CAAC,IAAI,uBAAuB;CACpC;AAED,0CAA0C;AAC1C,qBAAa,eAAgB,SAAQ,QAAQ;IAC5C,QAAQ,CAAC,IAAI,uBAAuB;CACpC;AAED,8DAA8D;AAC9D,qBAAa,kBAAmB,SAAQ,QAAQ;IAC/C,QAAQ,CAAC,IAAI,0BAA0B;CACvC;AAED,kDAAkD;AAClD,qBAAa,eAAgB,SAAQ,QAAQ;IAC5C,QAAQ,CAAC,IAAI,uBAAuB;CACpC;AAED,qDAAqD;AACrD,qBAAa,iBAAkB,SAAQ,QAAQ;IAC9C,QAAQ,CAAC,IAAI,0BAA0B;CACvC;AAED,gEAAgE;AAChE,qBAAa,UAAW,SAAQ,QAAQ;IACvC,QAAQ,CAAC,IAAI,iBAAiB;CAC9B;AAED,sEAAsE;AACtE,qBAAa,qBAAsB,SAAQ,QAAQ;IAClD,QAAQ,CAAC,IAAI,6BAA6B;CAC1C;AAED,2EAA2E;AAC3E,qBAAa,uBAAwB,SAAQ,QAAQ;IACpD,QAAQ,CAAC,IAAI,+BAA+B;IAC5C,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAI1C;AAED,uEAAuE;AACvE,qBAAa,mBAAoB,SAAQ,QAAQ;IAChD,QAAQ,CAAC,IAAI,2BAA2B;CACxC;AAED,yEAAyE;AACzE,qBAAa,iBAAkB,SAAQ,QAAQ;IAC9C,QAAQ,CAAC,IAAI,yBAAyB;CACtC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * DANGER: decode-without-verify, for debugging and inspection only.
3
+ */
4
+ import type { UntrustedJwt } from "../types.js";
5
+ /**
6
+ * DANGER: Decodes a JWT **without verifying the signature** and without
7
+ * validating a single claim - expired, forged and `alg: none` tokens all
8
+ * decode successfully. The returned {@link UntrustedJwt} is type-branded
9
+ * and incompatible with `VerifiedJwt`, so it cannot flow into
10
+ * authentication logic. Never base an auth decision on it.
11
+ *
12
+ * Legitimate uses: inspecting expired tokens while debugging, examining
13
+ * token structure without the key, observability of token contents.
14
+ * Since the token is unverified, fields the types mark mandatory may be
15
+ * absent at runtime.
16
+ *
17
+ * Throws only on malformed structure (base64url / UTF-8 / JSON) - never
18
+ * because a signature is missing or wrong.
19
+ */
20
+ export declare function unsafeDecode(token: string): UntrustedJwt;
21
+ //# sourceMappingURL=unsafe-decode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unsafe-decode.d.ts","sourceRoot":"","sources":["../../../../src/util/unsafe-decode.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAyB,YAAY,EAAE,MAAM,aAAa,CAAC;AAQvE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAiBxD"}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "lacewing",
3
+ "version": "1.0.0",
4
+ "description": "An opinionated JWT library that makes RFC 8725 (JWT Best Current Practices) the default behavior, not an optional configuration.",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=24"
8
+ },
9
+ "main": "dist/index.js",
10
+ "types": "dist/types/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/types/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./legacy/rs256": {
17
+ "types": "./dist/types/src/legacy/rs256.d.ts",
18
+ "default": "./dist/src/legacy/rs256.js"
19
+ },
20
+ "./legacy/rsa": {
21
+ "types": "./dist/types/src/legacy/rsa.d.ts",
22
+ "default": "./dist/src/legacy/rsa.js"
23
+ }
24
+ },
25
+ "scripts": {
26
+ "build": "tsc",
27
+ "typecheck": "tsc --noEmit",
28
+ "lint": "eslint .",
29
+ "lint:fix": "eslint . --fix",
30
+ "test": "node --import tsx --test \"tests/**/*.test.ts\"",
31
+ "test:tap": "node --import tsx --test --test-reporter=tap \"tests/**/*.test.ts\"",
32
+ "compliance": "node --import tsx tools/run-compliance.ts",
33
+ "demo": "node --import tsx examples/demo.ts",
34
+ "docs": "typedoc",
35
+ "changelog": "git-cliff -o CHANGELOG.md",
36
+ "prepare": "lefthook install",
37
+ "prepublishOnly": "npm run typecheck && npm run lint && npm test && npm run build"
38
+ },
39
+ "keywords": [
40
+ "jwt",
41
+ "jose",
42
+ "rfc8725",
43
+ "security",
44
+ "jwks",
45
+ "typescript"
46
+ ],
47
+ "author": "Smiduweorc",
48
+ "license": "MIT",
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/grMLEqomlkkU5Eeinz4brIrOVCUCkJuN/lacewing.git"
52
+ },
53
+ "devDependencies": {
54
+ "@commitlint/cli": "^21.2.1",
55
+ "@commitlint/config-conventional": "^21.2.0",
56
+ "@eslint/js": "^10.0.1",
57
+ "@types/node": "^26.1.1",
58
+ "eslint": "^10.7.0",
59
+ "fast-check": "^4.9.0",
60
+ "git-cliff": "^2.13.1",
61
+ "lefthook": "^2.1.10",
62
+ "tsx": "^4.23.0",
63
+ "typedoc": "^0.28.20",
64
+ "typescript": "^6.0.3",
65
+ "typescript-eslint": "^8.63.0"
66
+ },
67
+ "dependencies": {
68
+ "jose": "^6.2.3"
69
+ }
70
+ }