@draftlab/auth 0.0.2 → 0.0.4

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 (74) hide show
  1. package/dist/allow.d.ts +58 -1
  2. package/dist/allow.js +61 -2
  3. package/dist/client.d.ts +2 -3
  4. package/dist/client.js +2 -2
  5. package/dist/core.d.ts +128 -8
  6. package/dist/core.js +496 -12
  7. package/dist/error.d.ts +242 -1
  8. package/dist/error.js +235 -1
  9. package/dist/index.d.ts +1 -8
  10. package/dist/index.js +1 -12
  11. package/dist/keys.d.ts +1 -1
  12. package/dist/keys.js +138 -3
  13. package/dist/pkce.js +160 -1
  14. package/dist/provider/code.d.ts +211 -3
  15. package/dist/provider/code.js +1 -1
  16. package/dist/provider/facebook.d.ts +2 -3
  17. package/dist/provider/facebook.js +1 -5
  18. package/dist/provider/github.d.ts +2 -3
  19. package/dist/provider/github.js +1 -5
  20. package/dist/provider/google.d.ts +2 -3
  21. package/dist/provider/google.js +1 -5
  22. package/dist/provider/oauth2.d.ts +175 -3
  23. package/dist/provider/oauth2.js +153 -5
  24. package/dist/provider/password.d.ts +384 -3
  25. package/dist/provider/password.js +4 -4
  26. package/dist/provider/provider.d.ts +226 -2
  27. package/dist/random.js +85 -1
  28. package/dist/storage/memory.d.ts +1 -1
  29. package/dist/storage/memory.js +1 -1
  30. package/dist/storage/storage.d.ts +161 -1
  31. package/dist/storage/storage.js +60 -1
  32. package/dist/storage/turso.d.ts +1 -1
  33. package/dist/storage/turso.js +1 -1
  34. package/dist/storage/unstorage.d.ts +1 -1
  35. package/dist/storage/unstorage.js +1 -1
  36. package/dist/subject.d.ts +61 -2
  37. package/dist/themes/theme.d.ts +208 -1
  38. package/dist/themes/theme.js +118 -1
  39. package/dist/ui/base.js +420 -2
  40. package/dist/ui/code.d.ts +1 -3
  41. package/dist/ui/code.js +3 -4
  42. package/dist/ui/form.js +59 -1
  43. package/dist/ui/icon.js +190 -1
  44. package/dist/ui/password.d.ts +1 -3
  45. package/dist/ui/password.js +2 -3
  46. package/dist/ui/select.js +278 -4
  47. package/dist/util.d.ts +71 -1
  48. package/dist/util.js +106 -1
  49. package/package.json +2 -4
  50. package/dist/allow-CixonwTW.d.ts +0 -59
  51. package/dist/allow-DX5cehSc.js +0 -63
  52. package/dist/base-DRutbxgL.js +0 -422
  53. package/dist/code-DJxdFR7p.d.ts +0 -212
  54. package/dist/core-BZHEAefX.d.ts +0 -129
  55. package/dist/core-CDM5o4rs.js +0 -498
  56. package/dist/error-CWAdNAzm.d.ts +0 -243
  57. package/dist/error-DgAKK7b2.js +0 -237
  58. package/dist/form-6XKM_cOk.js +0 -61
  59. package/dist/icon-Ci5uqGB_.js +0 -192
  60. package/dist/keys-EEfxEGfO.js +0 -140
  61. package/dist/oauth2-B7-6Z7Lc.js +0 -155
  62. package/dist/oauth2-CXHukHf2.d.ts +0 -176
  63. package/dist/password-C4KLmO0O.d.ts +0 -385
  64. package/dist/pkce-276Za_rZ.js +0 -162
  65. package/dist/provider-tndlqCzp.d.ts +0 -227
  66. package/dist/random-SXMYlaVr.js +0 -87
  67. package/dist/select-BjySLL8I.js +0 -280
  68. package/dist/storage-BEaqEPNQ.js +0 -62
  69. package/dist/storage-CxKerLlc.d.ts +0 -162
  70. package/dist/subject-DMIMVtaT.d.ts +0 -62
  71. package/dist/theme-C9by7VXf.d.ts +0 -209
  72. package/dist/theme-CswaLtbW.js +0 -120
  73. package/dist/util-CSdHUFOo.js +0 -108
  74. package/dist/util-DbSKG1Xm.d.ts +0 -72
package/dist/error.d.ts CHANGED
@@ -1,2 +1,243 @@
1
- import { InvalidAccessTokenError, InvalidAuthorizationCodeError, InvalidRefreshTokenError, InvalidSubjectError, MissingParameterError, MissingProviderError, OauthError, OauthErrorType, UnauthorizedClientError, UnknownStateError } from "./error-CWAdNAzm.js";
1
+ //#region src/error.d.ts
2
+ /**
3
+ * Error classes and types for Draft Auth operations.
4
+ * Provides comprehensive error handling for OAuth 2.0 and authentication flows.
5
+ *
6
+ * ## Usage
7
+ *
8
+ * ```ts
9
+ * import {
10
+ * InvalidAuthorizationCodeError,
11
+ * OauthError,
12
+ * UnknownStateError
13
+ * } from "@draftauth/core/error"
14
+ *
15
+ * try {
16
+ * await client.exchange(code, redirectUri)
17
+ * } catch (error) {
18
+ * if (error instanceof InvalidAuthorizationCodeError) {
19
+ * // Handle invalid authorization code
20
+ * // Authorization code expired or invalid
21
+ * } else if (error instanceof OauthError) {
22
+ * // Handle OAuth-specific errors
23
+ * // OAuth error: error.error - error.description
24
+ * }
25
+ * }
26
+ * ```
27
+ *
28
+ * ## Error Categories
29
+ *
30
+ * - **OAuth Errors**: Standard OAuth error responses
31
+ * - **Token Errors**: Issues with access tokens, refresh tokens, and authorization codes
32
+ * - **Client Errors**: Problems with client configuration and authorization
33
+ * - **State Errors**: Session and flow state management issues
34
+ *
35
+ * @packageDocumentation
36
+ */
37
+ /**
38
+ * Standard OAuth error types
39
+ * These error codes are returned by OAuth authorization servers.
40
+ */
41
+ type OauthErrorType = "invalid_request" | "invalid_client" | "invalid_grant" | "invalid_token" | "invalid_redirect_uri" | "insufficient_scope" | "unauthorized_client" | "access_denied" | "unsupported_grant_type" | "server_error" | "temporarily_unavailable" | "unsupported_response_type";
42
+ /**
43
+ * Base OAuth error class for handling standard OAuth error responses.
44
+ * Contains both the error code and human-readable description.
45
+ */
46
+ declare class OauthError extends Error {
47
+ /** The OAuth error code as defined in the specification */
48
+ readonly error: OauthErrorType;
49
+ /** Human-readable description of the error */
50
+ readonly description: string;
51
+ /**
52
+ * Creates a new OAuth error with the specified error code and description.
53
+ *
54
+ * @param error - The OAuth error type
55
+ * @param description - Human-readable error description
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * throw new OauthError("invalid_grant", "Authorization code has expired")
60
+ * ```
61
+ */
62
+ constructor(error: OauthErrorType, description: string);
63
+ /**
64
+ * Converts the error to a standard OAuth JSON response format.
65
+ *
66
+ * @returns Object with error and error_description fields
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * const oauthError = new OauthError("invalid_request", "Missing parameter")
71
+ * return c.json(oauthError.toJSON(), 400)
72
+ * ```
73
+ */
74
+ toJSON(): {
75
+ error: OauthErrorType;
76
+ error_description: string;
77
+ };
78
+ }
79
+ /**
80
+ * Error thrown when a provider parameter is missing from the authorization request.
81
+ * Occurs when multiple providers are configured but no specific provider is selected.
82
+ */
83
+ declare class MissingProviderError extends OauthError {
84
+ /**
85
+ * Creates a missing provider error.
86
+ * Thrown when the provider query parameter is required but not provided.
87
+ */
88
+ constructor();
89
+ }
90
+ /**
91
+ * Error thrown when a required parameter is missing from a request.
92
+ * Used for validating OAuth request parameters.
93
+ */
94
+ declare class MissingParameterError extends OauthError {
95
+ /** The name of the missing parameter */
96
+ readonly parameter: string;
97
+ /**
98
+ * Creates a missing parameter error.
99
+ *
100
+ * @param parameter - The name of the missing parameter
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * throw new MissingParameterError("client_id")
105
+ * ```
106
+ */
107
+ constructor(parameter: string);
108
+ }
109
+ /**
110
+ * Error thrown when a client is not authorized to use a specific redirect URI.
111
+ * Prevents unauthorized clients from hijacking authorization codes.
112
+ */
113
+ declare class UnauthorizedClientError extends OauthError {
114
+ /** The client ID that attempted unauthorized access */
115
+ readonly clientID: string;
116
+ /**
117
+ * Creates an unauthorized client error.
118
+ *
119
+ * @param clientID - The client ID attempting unauthorized access
120
+ * @param redirectURI - The unauthorized redirect URI
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * throw new UnauthorizedClientError("malicious-client", "https://evil.com/callback")
125
+ * ```
126
+ */
127
+ constructor(clientID: string, redirectURI: string);
128
+ }
129
+ /**
130
+ * Error thrown when the authentication flow is in an unknown or invalid state.
131
+ *
132
+ * ## Common Causes
133
+ * - Session cookies have expired during the authentication flow
134
+ * - User switched browsers or devices mid-flow
135
+ * - Authentication state was manually tampered with
136
+ * - Server session storage was cleared
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * // In provider callback handling
141
+ * const state = await getAuthState(request)
142
+ * if (!state) {
143
+ * throw new UnknownStateError()
144
+ * }
145
+ * ```
146
+ */
147
+ declare class UnknownStateError extends Error {
148
+ /**
149
+ * Creates an unknown state error.
150
+ * Indicates that the authentication flow cannot continue due to missing state.
151
+ */
152
+ constructor();
153
+ }
154
+ /**
155
+ * Error thrown when a subject (user identifier) is invalid or malformed.
156
+ * Used during token verification and subject validation.
157
+ *
158
+ * @example
159
+ * ```ts
160
+ * // During token verification
161
+ * const subject = extractSubject(token)
162
+ * if (!isValidSubject(subject)) {
163
+ * throw new InvalidSubjectError()
164
+ * }
165
+ * ```
166
+ */
167
+ declare class InvalidSubjectError extends Error {
168
+ /**
169
+ * Creates an invalid subject error.
170
+ */
171
+ constructor();
172
+ }
173
+ /**
174
+ * Error thrown when a refresh token is invalid, expired, or revoked.
175
+ * Occurs during token refresh operations.
176
+ *
177
+ * @example
178
+ * ```ts
179
+ * // During token refresh
180
+ * try {
181
+ * const newTokens = await client.refresh(refreshToken)
182
+ * } catch (error) {
183
+ * if (error instanceof InvalidRefreshTokenError) {
184
+ * // Redirect user to login again
185
+ * redirectToLogin()
186
+ * }
187
+ * }
188
+ * ```
189
+ */
190
+ declare class InvalidRefreshTokenError extends Error {
191
+ /**
192
+ * Creates an invalid refresh token error.
193
+ */
194
+ constructor();
195
+ }
196
+ /**
197
+ * Error thrown when an access token is invalid, expired, or malformed.
198
+ * Occurs during token verification and API requests.
199
+ *
200
+ * @example
201
+ * ```ts
202
+ * // During API request
203
+ * try {
204
+ * const user = await api.getUser(accessToken)
205
+ * } catch (error) {
206
+ * if (error instanceof InvalidAccessTokenError) {
207
+ * // Try to refresh the token
208
+ * await refreshAccessToken()
209
+ * }
210
+ * }
211
+ * ```
212
+ */
213
+ declare class InvalidAccessTokenError extends Error {
214
+ /**
215
+ * Creates an invalid access token error.
216
+ */
217
+ constructor();
218
+ }
219
+ /**
220
+ * Error thrown when an authorization code is invalid, expired, or already used.
221
+ * Occurs during the token exchange step of the OAuth flow.
222
+ *
223
+ * @example
224
+ * ```ts
225
+ * // During authorization code exchange
226
+ * try {
227
+ * const tokens = await client.exchange(code, redirectUri)
228
+ * } catch (error) {
229
+ * if (error instanceof InvalidAuthorizationCodeError) {
230
+ * // Code may have expired or been used already
231
+ * redirectToAuthorize()
232
+ * }
233
+ * }
234
+ * ```
235
+ */
236
+ declare class InvalidAuthorizationCodeError extends Error {
237
+ /**
238
+ * Creates an invalid authorization code error.
239
+ */
240
+ constructor();
241
+ }
242
+ //#endregion
2
243
  export { InvalidAccessTokenError, InvalidAuthorizationCodeError, InvalidRefreshTokenError, InvalidSubjectError, MissingParameterError, MissingProviderError, OauthError, OauthErrorType, UnauthorizedClientError, UnknownStateError };
package/dist/error.js CHANGED
@@ -1,3 +1,237 @@
1
- import { InvalidAccessTokenError, InvalidAuthorizationCodeError, InvalidRefreshTokenError, InvalidSubjectError, MissingParameterError, MissingProviderError, OauthError, UnauthorizedClientError, UnknownStateError } from "./error-DgAKK7b2.js";
1
+ //#region src/error.ts
2
+ /**
3
+ * Base OAuth error class for handling standard OAuth error responses.
4
+ * Contains both the error code and human-readable description.
5
+ */
6
+ var OauthError = class extends Error {
7
+ /** The OAuth error code as defined in the specification */
8
+ error;
9
+ /** Human-readable description of the error */
10
+ description;
11
+ /**
12
+ * Creates a new OAuth error with the specified error code and description.
13
+ *
14
+ * @param error - The OAuth error type
15
+ * @param description - Human-readable error description
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * throw new OauthError("invalid_grant", "Authorization code has expired")
20
+ * ```
21
+ */
22
+ constructor(error, description) {
23
+ super(`${error} - ${description}`);
24
+ this.name = "OauthError";
25
+ this.error = error;
26
+ this.description = description;
27
+ }
28
+ /**
29
+ * Converts the error to a standard OAuth JSON response format.
30
+ *
31
+ * @returns Object with error and error_description fields
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const oauthError = new OauthError("invalid_request", "Missing parameter")
36
+ * return c.json(oauthError.toJSON(), 400)
37
+ * ```
38
+ */
39
+ toJSON() {
40
+ return {
41
+ error: this.error,
42
+ error_description: this.description
43
+ };
44
+ }
45
+ };
46
+ /**
47
+ * Error thrown when a provider parameter is missing from the authorization request.
48
+ * Occurs when multiple providers are configured but no specific provider is selected.
49
+ */
50
+ var MissingProviderError = class extends OauthError {
51
+ /**
52
+ * Creates a missing provider error.
53
+ * Thrown when the provider query parameter is required but not provided.
54
+ */
55
+ constructor() {
56
+ super("invalid_request", "Must specify `provider` query parameter if `select` callback on issuer is not specified");
57
+ this.name = "MissingProviderError";
58
+ }
59
+ };
60
+ /**
61
+ * Error thrown when a required parameter is missing from a request.
62
+ * Used for validating OAuth request parameters.
63
+ */
64
+ var MissingParameterError = class extends OauthError {
65
+ /** The name of the missing parameter */
66
+ parameter;
67
+ /**
68
+ * Creates a missing parameter error.
69
+ *
70
+ * @param parameter - The name of the missing parameter
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * throw new MissingParameterError("client_id")
75
+ * ```
76
+ */
77
+ constructor(parameter) {
78
+ super("invalid_request", `Missing parameter: ${parameter}`);
79
+ this.name = "MissingParameterError";
80
+ this.parameter = parameter;
81
+ }
82
+ };
83
+ /**
84
+ * Error thrown when a client is not authorized to use a specific redirect URI.
85
+ * Prevents unauthorized clients from hijacking authorization codes.
86
+ */
87
+ var UnauthorizedClientError = class extends OauthError {
88
+ /** The client ID that attempted unauthorized access */
89
+ clientID;
90
+ /**
91
+ * Creates an unauthorized client error.
92
+ *
93
+ * @param clientID - The client ID attempting unauthorized access
94
+ * @param redirectURI - The unauthorized redirect URI
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * throw new UnauthorizedClientError("malicious-client", "https://evil.com/callback")
99
+ * ```
100
+ */
101
+ constructor(clientID, redirectURI) {
102
+ super("unauthorized_client", `Client ${clientID} is not authorized to use this redirect_uri: ${redirectURI}`);
103
+ this.name = "UnauthorizedClientError";
104
+ this.clientID = clientID;
105
+ }
106
+ };
107
+ /**
108
+ * Error thrown when the authentication flow is in an unknown or invalid state.
109
+ *
110
+ * ## Common Causes
111
+ * - Session cookies have expired during the authentication flow
112
+ * - User switched browsers or devices mid-flow
113
+ * - Authentication state was manually tampered with
114
+ * - Server session storage was cleared
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * // In provider callback handling
119
+ * const state = await getAuthState(request)
120
+ * if (!state) {
121
+ * throw new UnknownStateError()
122
+ * }
123
+ * ```
124
+ */
125
+ var UnknownStateError = class extends Error {
126
+ /**
127
+ * Creates an unknown state error.
128
+ * Indicates that the authentication flow cannot continue due to missing state.
129
+ */
130
+ constructor() {
131
+ super("The browser was in an unknown state. This could be because certain cookies expired or the browser was switched in the middle of an authentication flow.");
132
+ this.name = "UnknownStateError";
133
+ }
134
+ };
135
+ /**
136
+ * Error thrown when a subject (user identifier) is invalid or malformed.
137
+ * Used during token verification and subject validation.
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * // During token verification
142
+ * const subject = extractSubject(token)
143
+ * if (!isValidSubject(subject)) {
144
+ * throw new InvalidSubjectError()
145
+ * }
146
+ * ```
147
+ */
148
+ var InvalidSubjectError = class extends Error {
149
+ /**
150
+ * Creates an invalid subject error.
151
+ */
152
+ constructor() {
153
+ super("Invalid subject");
154
+ this.name = "InvalidSubjectError";
155
+ }
156
+ };
157
+ /**
158
+ * Error thrown when a refresh token is invalid, expired, or revoked.
159
+ * Occurs during token refresh operations.
160
+ *
161
+ * @example
162
+ * ```ts
163
+ * // During token refresh
164
+ * try {
165
+ * const newTokens = await client.refresh(refreshToken)
166
+ * } catch (error) {
167
+ * if (error instanceof InvalidRefreshTokenError) {
168
+ * // Redirect user to login again
169
+ * redirectToLogin()
170
+ * }
171
+ * }
172
+ * ```
173
+ */
174
+ var InvalidRefreshTokenError = class extends Error {
175
+ /**
176
+ * Creates an invalid refresh token error.
177
+ */
178
+ constructor() {
179
+ super("Invalid refresh token");
180
+ this.name = "InvalidRefreshTokenError";
181
+ }
182
+ };
183
+ /**
184
+ * Error thrown when an access token is invalid, expired, or malformed.
185
+ * Occurs during token verification and API requests.
186
+ *
187
+ * @example
188
+ * ```ts
189
+ * // During API request
190
+ * try {
191
+ * const user = await api.getUser(accessToken)
192
+ * } catch (error) {
193
+ * if (error instanceof InvalidAccessTokenError) {
194
+ * // Try to refresh the token
195
+ * await refreshAccessToken()
196
+ * }
197
+ * }
198
+ * ```
199
+ */
200
+ var InvalidAccessTokenError = class extends Error {
201
+ /**
202
+ * Creates an invalid access token error.
203
+ */
204
+ constructor() {
205
+ super("Invalid access token");
206
+ this.name = "InvalidAccessTokenError";
207
+ }
208
+ };
209
+ /**
210
+ * Error thrown when an authorization code is invalid, expired, or already used.
211
+ * Occurs during the token exchange step of the OAuth flow.
212
+ *
213
+ * @example
214
+ * ```ts
215
+ * // During authorization code exchange
216
+ * try {
217
+ * const tokens = await client.exchange(code, redirectUri)
218
+ * } catch (error) {
219
+ * if (error instanceof InvalidAuthorizationCodeError) {
220
+ * // Code may have expired or been used already
221
+ * redirectToAuthorize()
222
+ * }
223
+ * }
224
+ * ```
225
+ */
226
+ var InvalidAuthorizationCodeError = class extends Error {
227
+ /**
228
+ * Creates an invalid authorization code error.
229
+ */
230
+ constructor() {
231
+ super("Invalid authorization code");
232
+ this.name = "InvalidAuthorizationCodeError";
233
+ }
234
+ };
2
235
 
236
+ //#endregion
3
237
  export { InvalidAccessTokenError, InvalidAuthorizationCodeError, InvalidRefreshTokenError, InvalidSubjectError, MissingParameterError, MissingProviderError, OauthError, UnauthorizedClientError, UnknownStateError };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,2 @@
1
- import "./allow-CixonwTW.js";
2
- import "./error-CWAdNAzm.js";
3
- import "./util-DbSKG1Xm.js";
4
- import "./subject-DMIMVtaT.js";
5
- import "./storage-CxKerLlc.js";
6
- import "./provider-tndlqCzp.js";
7
- import "./theme-C9by7VXf.js";
8
- import { issuer } from "./core-BZHEAefX.js";
1
+ import { issuer } from "./core.js";
9
2
  export { issuer };
package/dist/index.js CHANGED
@@ -1,14 +1,3 @@
1
- import "./util-CSdHUFOo.js";
2
- import "./allow-DX5cehSc.js";
3
- import "./error-DgAKK7b2.js";
4
- import "./pkce-276Za_rZ.js";
5
- import "./random-SXMYlaVr.js";
6
- import "./storage-BEaqEPNQ.js";
7
- import "./keys-EEfxEGfO.js";
8
- import "./theme-CswaLtbW.js";
9
- import "./base-DRutbxgL.js";
10
- import "./icon-Ci5uqGB_.js";
11
- import "./select-BjySLL8I.js";
12
- import { issuer } from "./core-CDM5o4rs.js";
1
+ import { issuer } from "./core.js";
13
2
 
14
3
  export { issuer };
package/dist/keys.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { StorageAdapter } from "./storage-CxKerLlc.js";
1
+ import { StorageAdapter } from "./storage/storage.js";
2
2
  import { CryptoKey, JWK } from "jose";
3
3
 
4
4
  //#region src/keys.d.ts
package/dist/keys.js CHANGED
@@ -1,5 +1,140 @@
1
- import "./random-SXMYlaVr.js";
2
- import "./storage-BEaqEPNQ.js";
3
- import { encryptionKeys, signingKeys } from "./keys-EEfxEGfO.js";
1
+ import { generateSecureToken } from "./random.js";
2
+ import { Storage } from "./storage/storage.js";
3
+ import { exportJWK, exportPKCS8, exportSPKI, generateKeyPair, importPKCS8, importSPKI } from "jose";
4
4
 
5
+ //#region src/keys.ts
6
+ /**
7
+ * Cryptographic key management for JWT signing and encryption operations.
8
+ * Handles automatic key generation, rotation, and storage for OAuth operations.
9
+ */
10
+ /** Elliptic Curve algorithm used for JWT signing operations */
11
+ const signingAlg = "ES256";
12
+ /** RSA algorithm used for token encryption operations */
13
+ const encryptionAlg = "RSA-OAEP-512";
14
+ /**
15
+ * Loads or generates signing keys for JWT operations.
16
+ * Returns existing valid keys, or generates new ones if none are available.
17
+ * Keys are automatically sorted by creation date (newest first).
18
+ *
19
+ * @param storage - Storage adapter for persistent key storage
20
+ * @returns Promise resolving to array of available signing key pairs
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const keys = await signingKeys(storage)
25
+ * const currentKey = keys[0] // Most recent key
26
+ *
27
+ * // Use for JWT signing
28
+ * const jwt = await new SignJWT(payload)
29
+ * .setProtectedHeader({ alg: currentKey.alg, kid: currentKey.id })
30
+ * .sign(currentKey.private)
31
+ * ```
32
+ */
33
+ const signingKeys = async (storage) => {
34
+ const results = [];
35
+ const scanner = Storage.scan(storage, ["signing:key"]);
36
+ for await (const [, value] of scanner) try {
37
+ const publicKey = await importSPKI(value.publicKey, value.alg, { extractable: true });
38
+ const privateKey = await importPKCS8(value.privateKey, value.alg);
39
+ const jwk$1 = await exportJWK(publicKey);
40
+ jwk$1.kid = value.id;
41
+ jwk$1.use = "sig";
42
+ results.push({
43
+ id: value.id,
44
+ alg: signingAlg,
45
+ created: new Date(value.created),
46
+ expired: value.expired ? new Date(value.expired) : void 0,
47
+ public: publicKey,
48
+ private: privateKey,
49
+ jwk: jwk$1
50
+ });
51
+ } catch {}
52
+ results.sort((a, b) => b.created.getTime() - a.created.getTime());
53
+ if (results.filter((item) => !item.expired).length) return results;
54
+ const key = await generateKeyPair(signingAlg, { extractable: true });
55
+ const serialized = {
56
+ id: generateSecureToken(16),
57
+ publicKey: await exportSPKI(key.publicKey),
58
+ privateKey: await exportPKCS8(key.privateKey),
59
+ created: Date.now(),
60
+ alg: signingAlg
61
+ };
62
+ await Storage.set(storage, ["signing:key", serialized.id], serialized);
63
+ const jwk = await exportJWK(key.publicKey);
64
+ jwk.kid = serialized.id;
65
+ jwk.use = "sig";
66
+ const newKeyPair = {
67
+ id: serialized.id,
68
+ alg: signingAlg,
69
+ created: new Date(serialized.created),
70
+ expired: serialized.expired ? new Date(serialized.expired) : void 0,
71
+ public: key.publicKey,
72
+ private: key.privateKey,
73
+ jwk
74
+ };
75
+ return [newKeyPair, ...results];
76
+ };
77
+ /**
78
+ * Loads or generates encryption keys for token encryption operations.
79
+ * Returns existing valid keys, or generates new ones if none are available.
80
+ * Keys are automatically sorted by creation date (newest first).
81
+ *
82
+ * @param storage - Storage adapter for persistent key storage
83
+ * @returns Promise resolving to array of available encryption key pairs
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * const keys = await encryptionKeys(storage)
88
+ * const currentKey = keys[0] // Most recent key
89
+ *
90
+ * // Use for token encryption
91
+ * const encrypted = await new EncryptJWT(payload)
92
+ * .setProtectedHeader({ alg: 'RSA-OAEP-512', enc: 'A256GCM' })
93
+ * .encrypt(currentKey.public)
94
+ * ```
95
+ */
96
+ const encryptionKeys = async (storage) => {
97
+ const results = [];
98
+ const scanner = Storage.scan(storage, ["encryption:key"]);
99
+ for await (const [, value] of scanner) try {
100
+ const publicKey = await importSPKI(value.publicKey, value.alg, { extractable: true });
101
+ const privateKey = await importPKCS8(value.privateKey, value.alg);
102
+ const jwk$1 = await exportJWK(publicKey);
103
+ jwk$1.kid = value.id;
104
+ results.push({
105
+ id: value.id,
106
+ alg: encryptionAlg,
107
+ created: new Date(value.created),
108
+ expired: value.expired ? new Date(value.expired) : void 0,
109
+ public: publicKey,
110
+ private: privateKey,
111
+ jwk: jwk$1
112
+ });
113
+ } catch {}
114
+ results.sort((a, b) => b.created.getTime() - a.created.getTime());
115
+ if (results.filter((item) => !item.expired).length) return results;
116
+ const key = await generateKeyPair(encryptionAlg, { extractable: true });
117
+ const serialized = {
118
+ id: generateSecureToken(16),
119
+ publicKey: await exportSPKI(key.publicKey),
120
+ privateKey: await exportPKCS8(key.privateKey),
121
+ created: Date.now(),
122
+ alg: encryptionAlg
123
+ };
124
+ await Storage.set(storage, ["encryption:key", serialized.id], serialized);
125
+ const jwk = await exportJWK(key.publicKey);
126
+ jwk.kid = serialized.id;
127
+ const newKeyPair = {
128
+ id: serialized.id,
129
+ alg: encryptionAlg,
130
+ created: new Date(serialized.created),
131
+ expired: serialized.expired ? new Date(serialized.expired) : void 0,
132
+ public: key.publicKey,
133
+ private: key.privateKey,
134
+ jwk
135
+ };
136
+ return [newKeyPair, ...results];
137
+ };
138
+
139
+ //#endregion
5
140
  export { encryptionKeys, signingKeys };