@aura-stack/auth 0.1.0 → 0.2.0-rc.1

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 (111) hide show
  1. package/dist/@types/index.d.ts +5 -5
  2. package/dist/@types/router.d.d.ts +5 -5
  3. package/dist/@types/utility.d.ts +1 -5
  4. package/dist/actions/callback/access-token.cjs +95 -74
  5. package/dist/actions/callback/access-token.d.ts +7 -7
  6. package/dist/actions/callback/access-token.js +5 -3
  7. package/dist/actions/callback/callback.cjs +171 -249
  8. package/dist/actions/callback/callback.d.ts +6 -6
  9. package/dist/actions/callback/callback.js +10 -10
  10. package/dist/actions/callback/userinfo.cjs +81 -57
  11. package/dist/actions/callback/userinfo.d.ts +5 -5
  12. package/dist/actions/callback/userinfo.js +7 -5
  13. package/dist/actions/csrfToken/csrfToken.cjs +36 -105
  14. package/dist/actions/csrfToken/csrfToken.js +6 -6
  15. package/dist/actions/index.cjs +309 -444
  16. package/dist/actions/index.d.ts +5 -5
  17. package/dist/actions/index.js +19 -19
  18. package/dist/actions/session/session.cjs +25 -109
  19. package/dist/actions/session/session.js +4 -5
  20. package/dist/actions/signIn/authorization.cjs +96 -87
  21. package/dist/actions/signIn/authorization.d.ts +5 -5
  22. package/dist/actions/signIn/authorization.js +5 -5
  23. package/dist/actions/signIn/signIn.cjs +133 -242
  24. package/dist/actions/signIn/signIn.d.ts +6 -6
  25. package/dist/actions/signIn/signIn.js +8 -9
  26. package/dist/actions/signOut/signOut.cjs +136 -282
  27. package/dist/actions/signOut/signOut.js +8 -9
  28. package/dist/assert.cjs +5 -0
  29. package/dist/assert.d.ts +10 -1
  30. package/dist/assert.js +3 -1
  31. package/dist/chunk-3EUWD5BB.js +63 -0
  32. package/dist/chunk-6R2YZ4AC.js +22 -0
  33. package/dist/chunk-A3N4PVAT.js +70 -0
  34. package/dist/chunk-B737EUJV.js +22 -0
  35. package/dist/{chunk-256KIVJL.js → chunk-CXLATHS5.js} +53 -9
  36. package/dist/{chunk-6SM22VVJ.js → chunk-EIL2FPSS.js} +5 -1
  37. package/dist/{chunk-VFTYH33W.js → chunk-EMKJA2GJ.js} +36 -8
  38. package/dist/{chunk-UJJ7R56J.js → chunk-GA2SMTJO.js} +16 -10
  39. package/dist/chunk-HP34YGGJ.js +22 -0
  40. package/dist/chunk-HT4YLL7N.js +35 -0
  41. package/dist/{chunk-EBPE35JT.js → chunk-IUYZQTJV.js} +0 -1
  42. package/dist/{chunk-RLT4RFKV.js → chunk-IVET23KF.js} +21 -8
  43. package/dist/{chunk-XXJKNKGQ.js → chunk-JVFTCTTE.js} +9 -13
  44. package/dist/chunk-KSWLO5ZU.js +102 -0
  45. package/dist/{chunk-GZU3RBTB.js → chunk-N2APGLXA.js} +19 -10
  46. package/dist/{chunk-CAKJT3KS.js → chunk-N4SX7TZT.js} +21 -17
  47. package/dist/chunk-RRLIF4PQ.js +55 -0
  48. package/dist/chunk-TLE4PXY3.js +39 -0
  49. package/dist/chunk-W6LG7BFW.js +197 -0
  50. package/dist/{chunk-HMRKN75I.js → chunk-YRCB5FLE.js} +14 -9
  51. package/dist/chunk-ZNCZVF6U.js +14 -0
  52. package/dist/cookie.cjs +140 -99
  53. package/dist/cookie.d.ts +35 -44
  54. package/dist/cookie.js +10 -17
  55. package/dist/errors.cjs +85 -0
  56. package/dist/errors.d.ts +49 -0
  57. package/dist/errors.js +18 -0
  58. package/dist/{index-DpfbvTZ_.d.ts → index-DkaLJFn8.d.ts} +192 -61
  59. package/dist/index.cjs +543 -443
  60. package/dist/index.d.ts +6 -6
  61. package/dist/index.js +42 -28
  62. package/dist/jose.cjs +25 -14
  63. package/dist/jose.d.ts +4 -1
  64. package/dist/jose.js +5 -4
  65. package/dist/oauth/bitbucket.d.ts +5 -5
  66. package/dist/oauth/discord.cjs +0 -1
  67. package/dist/oauth/discord.d.ts +5 -5
  68. package/dist/oauth/discord.js +1 -1
  69. package/dist/oauth/figma.d.ts +5 -5
  70. package/dist/oauth/github.d.ts +5 -5
  71. package/dist/oauth/gitlab.d.ts +5 -5
  72. package/dist/oauth/index.cjs +176 -6
  73. package/dist/oauth/index.d.ts +5 -5
  74. package/dist/oauth/index.js +19 -4
  75. package/dist/oauth/mailchimp.cjs +46 -0
  76. package/dist/oauth/mailchimp.d.ts +7 -0
  77. package/dist/oauth/mailchimp.js +6 -0
  78. package/dist/oauth/pinterest.cjs +46 -0
  79. package/dist/oauth/pinterest.d.ts +7 -0
  80. package/dist/oauth/pinterest.js +6 -0
  81. package/dist/oauth/spotify.d.ts +5 -5
  82. package/dist/oauth/strava.cjs +46 -0
  83. package/dist/oauth/strava.d.ts +7 -0
  84. package/dist/oauth/strava.js +6 -0
  85. package/dist/oauth/x.d.ts +5 -5
  86. package/dist/{response.cjs → request.cjs} +14 -10
  87. package/dist/request.d.ts +13 -0
  88. package/dist/request.js +6 -0
  89. package/dist/schemas.cjs +43 -37
  90. package/dist/schemas.d.ts +67 -64
  91. package/dist/schemas.js +3 -1
  92. package/dist/secure.cjs +32 -24
  93. package/dist/secure.d.ts +5 -5
  94. package/dist/secure.js +4 -3
  95. package/dist/utils.cjs +90 -15
  96. package/dist/utils.d.ts +11 -2
  97. package/dist/utils.js +8 -4
  98. package/package.json +8 -7
  99. package/dist/chunk-FJUDBLCP.js +0 -59
  100. package/dist/chunk-HGJ4TXY4.js +0 -137
  101. package/dist/chunk-JAPMIE6S.js +0 -10
  102. package/dist/chunk-LLR722CL.js +0 -96
  103. package/dist/chunk-SJPDVKUS.js +0 -112
  104. package/dist/chunk-SMQO5WD7.js +0 -30
  105. package/dist/chunk-UTDLUEEG.js +0 -31
  106. package/dist/chunk-ZV4BH47P.js +0 -154
  107. package/dist/error.cjs +0 -88
  108. package/dist/error.d.ts +0 -62
  109. package/dist/error.js +0 -16
  110. package/dist/response.d.ts +0 -10
  111. package/dist/response.js +0 -6
@@ -33,56 +33,28 @@ __export(signOut_exports, {
33
33
  signOutAction: () => signOutAction
34
34
  });
35
35
  module.exports = __toCommonJS(signOut_exports);
36
- var import_zod = __toESM(require("zod"), 1);
36
+ var import_zod2 = require("zod");
37
37
  var import_router2 = require("@aura-stack/router");
38
38
 
39
39
  // src/secure.ts
40
- var import_node_crypto = __toESM(require("crypto"), 1);
40
+ var import_crypto = __toESM(require("crypto"), 1);
41
41
 
42
42
  // src/utils.ts
43
43
  var import_router = require("@aura-stack/router");
44
44
 
45
- // src/error.ts
46
- var AuthError = class extends Error {
47
- constructor(type, message) {
48
- super(message);
49
- this.type = type;
50
- this.name = "AuthError";
45
+ // src/errors.ts
46
+ var AuthSecurityError = class extends Error {
47
+ type = "AUTH_SECURITY_ERROR";
48
+ code;
49
+ constructor(code, message, options2) {
50
+ super(message, options2);
51
+ this.code = code;
52
+ this.name = new.target.name;
53
+ Error.captureStackTrace(this, new.target);
51
54
  }
52
55
  };
53
- var InvalidCsrfTokenError = class extends AuthError {
54
- constructor(message = "The provided CSRF token is invalid or has expired") {
55
- super("invalid_csrf_token", message);
56
- this.name = "InvalidCsrfTokenError";
57
- }
58
- };
59
- var InvalidRedirectToError = class extends AuthError {
60
- constructor(message = "The redirectTo parameter does not match the hosted origin.") {
61
- super("invalid_redirect_to", message);
62
- this.name = "InvalidRedirectToError";
63
- }
64
- };
65
- var isAuthError = (error) => {
66
- return error instanceof AuthError;
67
- };
68
- var ERROR_RESPONSE = {
69
- AUTHORIZATION: {
70
- INVALID_REQUEST: "invalid_request",
71
- UNAUTHORIZED_CLIENT: "unauthorized_client",
72
- ACCESS_DENIED: "access_denied",
73
- UNSUPPORTED_RESPONSE_TYPE: "unsupported_response_type",
74
- INVALID_SCOPE: "invalid_scope",
75
- SERVER_ERROR: "server_error",
76
- TEMPORARILY_UNAVAILABLE: "temporarily_unavailable"
77
- },
78
- ACCESS_TOKEN: {
79
- INVALID_REQUEST: "invalid_request",
80
- INVALID_CLIENT: "invalid_client",
81
- INVALID_GRANT: "invalid_grant",
82
- UNAUTHORIZED_CLIENT: "unauthorized_client",
83
- UNSUPPORTED_GRANT_TYPE: "unsupported_grant_type",
84
- INVALID_SCOPE: "invalid_scope"
85
- }
56
+ var isAuthSecurityError = (error) => {
57
+ return error instanceof AuthSecurityError;
86
58
  };
87
59
 
88
60
  // src/utils.ts
@@ -90,9 +62,9 @@ var equals = (a, b) => {
90
62
  if (a === null || b === null || a === void 0 || b === void 0) return false;
91
63
  return a === b;
92
64
  };
93
- var sanitizeURL = (url2) => {
65
+ var sanitizeURL = (url) => {
94
66
  try {
95
- let decodedURL = decodeURIComponent(url2).trim();
67
+ let decodedURL = decodeURIComponent(url).trim();
96
68
  const protocolMatch = decodedURL.match(/^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)/);
97
69
  let protocol = "";
98
70
  let rest = decodedURL;
@@ -120,36 +92,52 @@ var sanitizeURL = (url2) => {
120
92
  }
121
93
  return sanitized;
122
94
  } catch {
123
- return url2.trim();
95
+ return url.trim();
124
96
  }
125
97
  };
126
98
  var getNormalizedOriginPath = (path) => {
127
99
  try {
128
- const url2 = new URL(path);
129
- url2.hash = "";
130
- url2.search = "";
131
- return `${url2.origin}${url2.pathname}`;
100
+ const url = new URL(path);
101
+ url.hash = "";
102
+ url.search = "";
103
+ return `${url.origin}${url.pathname}`;
132
104
  } catch {
133
105
  return sanitizeURL(path);
134
106
  }
135
107
  };
136
108
 
109
+ // src/assert.ts
110
+ var isValidURL = (value) => {
111
+ if (value.includes("\r\n") || value.includes("\n") || value.includes("\r")) return false;
112
+ const regex = /^https?:\/\/(?:[a-zA-Z0-9._-]+|localhost|\[[0-9a-fA-F:]+\])(?::\d{1,5})?(?:\/[a-zA-Z0-9._~!$&'()*+,;=:@-]*)*\/?$/;
113
+ return regex.test(value);
114
+ };
115
+ var isJWTPayloadWithToken = (payload) => {
116
+ return typeof payload === "object" && payload !== null && "token" in payload && typeof payload?.token === "string";
117
+ };
118
+
137
119
  // src/secure.ts
138
120
  var verifyCSRF = async (jose, cookie, header) => {
139
121
  try {
140
- const { token: cookieToken } = await jose.verifyJWS(cookie);
141
- const { token: headerToken } = await jose.verifyJWS(header);
142
- const cookieBuffer = Buffer.from(cookieToken);
143
- const headerBuffer = Buffer.from(headerToken);
122
+ const cookiePayload = await jose.verifyJWS(cookie);
123
+ const headerPayload = await jose.verifyJWS(header);
124
+ if (!isJWTPayloadWithToken(cookiePayload)) {
125
+ throw new AuthSecurityError("CSRF_TOKEN_INVALID", "Cookie payload missing token field.");
126
+ }
127
+ if (!isJWTPayloadWithToken(headerPayload)) {
128
+ throw new AuthSecurityError("CSRF_TOKEN_INVALID", "Header payload missing token field.");
129
+ }
130
+ const cookieBuffer = Buffer.from(cookiePayload.token);
131
+ const headerBuffer = Buffer.from(headerPayload.token);
144
132
  if (!equals(headerBuffer.length, cookieBuffer.length)) {
145
- throw new InvalidCsrfTokenError();
133
+ throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
146
134
  }
147
- if (!import_node_crypto.default.timingSafeEqual(cookieBuffer, headerBuffer)) {
148
- throw new InvalidCsrfTokenError();
135
+ if (!import_crypto.default.timingSafeEqual(cookieBuffer, headerBuffer)) {
136
+ throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
149
137
  }
150
138
  return true;
151
139
  } catch {
152
- throw new InvalidCsrfTokenError();
140
+ throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
153
141
  }
154
142
  };
155
143
 
@@ -161,46 +149,49 @@ var cacheControl = {
161
149
  Vary: "Cookie"
162
150
  };
163
151
 
164
- // src/response.ts
165
- var AuraResponse = class extends Response {
166
- static json(body, init) {
167
- return Response.json(body, init);
168
- }
152
+ // src/cookie.ts
153
+ var import_cookie = require("@aura-stack/router/cookie");
154
+ var defaultCookieOptions = {
155
+ httpOnly: true,
156
+ sameSite: "lax",
157
+ path: "/",
158
+ maxAge: 60 * 60 * 24 * 15
169
159
  };
170
-
171
- // src/assert.ts
172
- var isRequest = (value) => {
173
- return typeof Request !== "undefined" && value instanceof Request;
160
+ var oauthCookieOptions = {
161
+ httpOnly: true,
162
+ maxAge: 5 * 60,
163
+ sameSite: "lax",
164
+ expires: new Date(Date.now() + 5 * 60 * 1e3)
174
165
  };
175
- var isValidURL = (value) => {
176
- if (value.includes("\r\n") || value.includes("\n") || value.includes("\r")) return false;
177
- const regex = /^https?:\/\/(?:[a-zA-Z0-9._-]+|localhost|\[[0-9a-fA-F:]+\])(?::\d{1,5})?(?:\/[a-zA-Z0-9._~!$&'()*+,;=:@-]*)*\/?$/;
178
- return regex.test(value);
166
+ var expiredCookieAttributes = {
167
+ ...defaultCookieOptions,
168
+ expires: /* @__PURE__ */ new Date(0),
169
+ maxAge: 0
179
170
  };
180
171
 
181
172
  // src/schemas.ts
182
- var import_v4 = require("zod/v4");
183
- var OAuthProviderConfigSchema = (0, import_v4.object)({
184
- authorizeURL: (0, import_v4.url)(),
185
- accessToken: (0, import_v4.url)(),
186
- scope: (0, import_v4.string)().optional(),
187
- userInfo: (0, import_v4.url)(),
188
- responseType: (0, import_v4.enum)(["code", "token", "id_token"]),
189
- clientId: (0, import_v4.string)(),
190
- clientSecret: (0, import_v4.string)()
173
+ var import_zod = require("zod");
174
+ var OAuthProviderConfigSchema = (0, import_zod.object)({
175
+ authorizeURL: (0, import_zod.string)().url(),
176
+ accessToken: (0, import_zod.string)().url(),
177
+ scope: (0, import_zod.string)().optional(),
178
+ userInfo: (0, import_zod.string)().url(),
179
+ responseType: (0, import_zod.enum)(["code", "token", "id_token"]),
180
+ clientId: (0, import_zod.string)(),
181
+ clientSecret: (0, import_zod.string)()
191
182
  });
192
183
  var OAuthAuthorization = OAuthProviderConfigSchema.extend({
193
- redirectURI: (0, import_v4.string)(),
194
- state: (0, import_v4.string)(),
195
- codeChallenge: (0, import_v4.string)(),
196
- codeChallengeMethod: (0, import_v4.enum)(["plain", "S256"])
184
+ redirectURI: (0, import_zod.string)(),
185
+ state: (0, import_zod.string)(),
186
+ codeChallenge: (0, import_zod.string)(),
187
+ codeChallengeMethod: (0, import_zod.enum)(["plain", "S256"])
197
188
  });
198
- var OAuthAuthorizationResponse = (0, import_v4.object)({
199
- state: (0, import_v4.string)(),
200
- code: (0, import_v4.string)()
189
+ var OAuthAuthorizationResponse = (0, import_zod.object)({
190
+ state: (0, import_zod.string)({ message: "Missing state parameter in the OAuth authorization response." }),
191
+ code: (0, import_zod.string)({ message: "Missing code parameter in the OAuth authorization response." })
201
192
  });
202
- var OAuthAuthorizationErrorResponse = (0, import_v4.object)({
203
- error: (0, import_v4.enum)([
193
+ var OAuthAuthorizationErrorResponse = (0, import_zod.object)({
194
+ error: (0, import_zod.enum)([
204
195
  "invalid_request",
205
196
  "unauthorized_client",
206
197
  "access_denied",
@@ -209,24 +200,24 @@ var OAuthAuthorizationErrorResponse = (0, import_v4.object)({
209
200
  "server_error",
210
201
  "temporarily_unavailable"
211
202
  ]),
212
- error_description: (0, import_v4.string)().optional(),
213
- error_uri: (0, import_v4.string)().optional(),
214
- state: (0, import_v4.string)()
203
+ error_description: (0, import_zod.string)().optional(),
204
+ error_uri: (0, import_zod.string)().optional(),
205
+ state: (0, import_zod.string)()
215
206
  });
216
207
  var OAuthAccessToken = OAuthProviderConfigSchema.extend({
217
- redirectURI: (0, import_v4.string)(),
218
- code: (0, import_v4.string)(),
219
- codeVerifier: (0, import_v4.string)().min(43).max(128)
208
+ redirectURI: (0, import_zod.string)(),
209
+ code: (0, import_zod.string)(),
210
+ codeVerifier: (0, import_zod.string)().min(43).max(128)
220
211
  });
221
- var OAuthAccessTokenResponse = (0, import_v4.object)({
222
- access_token: (0, import_v4.string)(),
223
- token_type: (0, import_v4.string)(),
224
- expires_in: (0, import_v4.number)().optional(),
225
- refresh_token: (0, import_v4.string)().optional(),
226
- scope: (0, import_v4.string)().optional()
212
+ var OAuthAccessTokenResponse = (0, import_zod.object)({
213
+ access_token: (0, import_zod.string)(),
214
+ token_type: (0, import_zod.string)().optional(),
215
+ expires_in: (0, import_zod.number)().optional(),
216
+ refresh_token: (0, import_zod.string)().optional(),
217
+ scope: (0, import_zod.string)().optional().or((0, import_zod.null)())
227
218
  });
228
- var OAuthAccessTokenErrorResponse = (0, import_v4.object)({
229
- error: (0, import_v4.enum)([
219
+ var OAuthAccessTokenErrorResponse = (0, import_zod.object)({
220
+ error: (0, import_zod.enum)([
230
221
  "invalid_request",
231
222
  "invalid_client",
232
223
  "invalid_grant",
@@ -234,12 +225,16 @@ var OAuthAccessTokenErrorResponse = (0, import_v4.object)({
234
225
  "unsupported_grant_type",
235
226
  "invalid_scope"
236
227
  ]),
237
- error_description: (0, import_v4.string)().optional(),
238
- error_uri: (0, import_v4.string)().optional()
228
+ error_description: (0, import_zod.string)().optional(),
229
+ error_uri: (0, import_zod.string)().optional()
239
230
  });
240
- var OAuthErrorResponse = (0, import_v4.object)({
241
- error: (0, import_v4.string)(),
242
- error_description: (0, import_v4.string)().optional()
231
+ var OAuthErrorResponse = (0, import_zod.object)({
232
+ error: (0, import_zod.string)(),
233
+ error_description: (0, import_zod.string)().optional()
234
+ });
235
+ var OAuthEnvSchema = (0, import_zod.object)({
236
+ clientId: import_zod.z.string().min(1, "OAuth Client ID is required in the environment variables."),
237
+ clientSecret: import_zod.z.string().min(1, "OAuth Client Secret is required in the environment variables.")
243
238
  });
244
239
 
245
240
  // src/actions/signIn/authorization.ts
@@ -265,15 +260,18 @@ var createRedirectTo = (request, redirectTo, trustedProxyHeaders) => {
265
260
  }
266
261
  const redirectToURL = new URL(sanitizeURL(getNormalizedOriginPath(redirectTo)));
267
262
  if (!isValidURL(redirectTo) || !equals(redirectToURL.origin, hostedURL.origin)) {
268
- throw new InvalidRedirectToError();
263
+ throw new AuthSecurityError(
264
+ "POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
265
+ "The redirectTo parameter does not match the hosted origin."
266
+ );
269
267
  }
270
268
  return sanitizeURL(redirectToURL.pathname);
271
269
  }
272
270
  if (referer) {
273
271
  const refererURL = new URL(sanitizeURL(referer));
274
272
  if (!isValidURL(referer) || !equals(refererURL.origin, hostedURL.origin)) {
275
- throw new AuthError(
276
- ERROR_RESPONSE.AUTHORIZATION.INVALID_REQUEST,
273
+ throw new AuthSecurityError(
274
+ "POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
277
275
  "The referer of the request does not match the hosted origin."
278
276
  );
279
277
  }
@@ -282,133 +280,25 @@ var createRedirectTo = (request, redirectTo, trustedProxyHeaders) => {
282
280
  if (origin) {
283
281
  const originURL = new URL(sanitizeURL(getNormalizedOriginPath(origin)));
284
282
  if (!isValidURL(origin) || !equals(originURL.origin, hostedURL.origin)) {
285
- throw new AuthError(ERROR_RESPONSE.AUTHORIZATION.INVALID_REQUEST, "Invalid origin (potential CSRF).");
283
+ throw new AuthSecurityError("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", "Invalid origin (potential CSRF).");
286
284
  }
287
285
  return sanitizeURL(originURL.pathname);
288
286
  }
289
287
  return "/";
290
288
  } catch (error) {
291
- if (isAuthError(error)) {
289
+ if (isAuthSecurityError(error)) {
292
290
  throw error;
293
291
  }
294
- throw new AuthError(ERROR_RESPONSE.AUTHORIZATION.INVALID_REQUEST, "Invalid origin (potential CSRF).");
295
- }
296
- };
297
-
298
- // src/cookie.ts
299
- var import_cookie = require("cookie");
300
- var import_cookie2 = require("cookie");
301
- var COOKIE_NAME = "aura-auth";
302
- var defaultCookieOptions = {
303
- httpOnly: true,
304
- sameSite: "lax",
305
- path: "/",
306
- maxAge: 60 * 60 * 24 * 15
307
- };
308
- var defaultStandardCookieConfig = {
309
- secure: false,
310
- httpOnly: true,
311
- prefix: ""
312
- };
313
- var defaultSecureCookieConfig = {
314
- secure: true,
315
- prefix: "__Secure-"
316
- };
317
- var defaultHostCookieConfig = {
318
- secure: true,
319
- prefix: "__Host-",
320
- path: "/",
321
- domain: void 0
322
- };
323
- var expiredCookieOptions = {
324
- ...defaultCookieOptions,
325
- expires: /* @__PURE__ */ new Date(0),
326
- maxAge: 0
327
- };
328
- var defineDefaultCookieOptions = (options2) => {
329
- return {
330
- name: options2?.name ?? COOKIE_NAME,
331
- prefix: options2?.prefix ?? (options2?.secure ? "__Secure-" : ""),
332
- ...defaultCookieOptions,
333
- ...options2
334
- };
335
- };
336
- var setCookie = (cookieName, value, options2) => {
337
- const { prefix, name } = defineDefaultCookieOptions(options2);
338
- const cookieNameWithPrefix = `${prefix}${name}.${cookieName}`;
339
- return (0, import_cookie.serialize)(cookieNameWithPrefix, value, {
340
- ...defaultCookieOptions,
341
- ...options2
342
- });
343
- };
344
- var getCookie = (petition, cookie, options2, optional = false) => {
345
- const cookies = isRequest(petition) ? petition.headers.get("Cookie") : petition.headers.getSetCookie().join("; ");
346
- if (!cookies) {
347
- if (optional) {
348
- return "";
349
- }
350
- throw new AuthError("invalid_request", "No cookies found. There is no active session");
292
+ throw new AuthSecurityError("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", "Invalid origin (potential CSRF).");
351
293
  }
352
- const { name, prefix } = defineDefaultCookieOptions(options2);
353
- const parsedCookies = (0, import_cookie.parse)(cookies);
354
- const value = parsedCookies[`${prefix}${name}.${cookie}`];
355
- if (value === void 0) {
356
- if (optional) {
357
- return "";
358
- }
359
- throw new AuthError("invalid_request", `Cookie "${cookie}" not found. There is no active session`);
360
- }
361
- return value;
362
- };
363
- var secureCookieOptions = (request, cookieOptions, trustedProxyHeaders) => {
364
- const name = cookieOptions.name ?? COOKIE_NAME;
365
- const isSecure = trustedProxyHeaders ? request.url.startsWith("https://") || request.headers.get("X-Forwarded-Proto") === "https" || request.headers.get("Forwarded")?.includes("proto=https") : request.url.startsWith("https://");
366
- if (!cookieOptions.options?.httpOnly) {
367
- console.warn(
368
- "[WARNING]: Cookie is configured without HttpOnly. This allows JavaScript access via document.cookie and increases XSS risk."
369
- );
370
- }
371
- if (cookieOptions.options?.domain === "*") {
372
- console.warn("[WARNING]: Cookie 'Domain' is set to '*', which is insecure. Avoid wildcard domains.");
373
- }
374
- if (!isSecure) {
375
- const options2 = cookieOptions.options;
376
- if (options2?.secure) {
377
- console.warn(
378
- "[WARNING]: The 'Secure' attribute will be disabled for this cookie. Serve over HTTPS to enforce Secure cookies."
379
- );
380
- }
381
- if (options2?.sameSite == "none") {
382
- console.warn("[WARNING]: SameSite=None without a secure connection can be blocked by browsers.");
383
- }
384
- if (process.env.NODE_ENV === "production") {
385
- console.warn("[WARNING]: In production, ensure cookies are served over HTTPS to maintain security.");
386
- }
387
- return {
388
- ...defaultCookieOptions,
389
- ...cookieOptions.options,
390
- sameSite: options2?.sameSite === "none" ? "lax" : options2?.sameSite ?? "lax",
391
- ...defaultStandardCookieConfig,
392
- name
393
- };
394
- }
395
- return cookieOptions.strategy === "host" ? {
396
- ...defaultCookieOptions,
397
- ...cookieOptions.options,
398
- ...defaultHostCookieConfig,
399
- name
400
- } : { ...defaultCookieOptions, ...cookieOptions.options, ...defaultSecureCookieConfig, name };
401
- };
402
- var expireCookie = (name, options2) => {
403
- return setCookie(name, "", { ...options2, ...expiredCookieOptions });
404
294
  };
405
295
 
406
296
  // src/actions/signOut/signOut.ts
407
297
  var config = (0, import_router2.createEndpointConfig)({
408
298
  schemas: {
409
- searchParams: import_zod.default.object({
410
- token_type_hint: import_zod.default.literal("session_token"),
411
- redirectTo: import_zod.default.string().optional()
299
+ searchParams: import_zod2.z.object({
300
+ token_type_hint: import_zod2.z.literal("session_token"),
301
+ redirectTo: import_zod2.z.string().optional()
412
302
  })
413
303
  }
414
304
  });
@@ -420,67 +310,31 @@ var signOutAction = (0, import_router2.createEndpoint)(
420
310
  request,
421
311
  headers,
422
312
  searchParams: { redirectTo },
423
- context: { cookies, jose, trustedProxyHeaders }
313
+ context: { jose, cookies }
424
314
  } = ctx;
425
- try {
426
- const cookiesOptions = secureCookieOptions(request, cookies, trustedProxyHeaders);
427
- const session = getCookie(request, "sessionToken", cookiesOptions);
428
- const csrfToken = getCookie(request, "csrfToken", {
429
- ...cookiesOptions,
430
- prefix: cookiesOptions.secure ? "__Host-" : ""
431
- });
432
- const header = headers.get("X-CSRF-Token");
433
- if (!header || !session || !csrfToken) {
434
- throw new Error("Missing CSRF token or session token");
435
- }
436
- await verifyCSRF(jose, csrfToken, header);
437
- await jose.decodeJWT(session);
438
- const normalizedOriginPath = getNormalizedOriginPath(request.url);
439
- const location = createRedirectTo(
440
- new Request(normalizedOriginPath, {
441
- headers
442
- }),
443
- redirectTo
444
- );
445
- const responseHeaders = new Headers(cacheControl);
446
- responseHeaders.append("Set-Cookie", expireCookie("sessionToken", cookiesOptions));
447
- responseHeaders.append(
448
- "Set-Cookie",
449
- expireCookie("csrfToken", { ...cookiesOptions, prefix: cookiesOptions.secure ? "__Host-" : "" })
450
- );
451
- responseHeaders.append("Location", location);
452
- return Response.json(
453
- { message: "Signed out successfully" },
454
- { status: import_router2.statusCode.ACCEPTED, headers: responseHeaders }
455
- );
456
- } catch (error) {
457
- if (error instanceof InvalidCsrfTokenError) {
458
- return AuraResponse.json(
459
- {
460
- error: "invalid_csrf_token",
461
- error_description: "The provided CSRF token is invalid or has expired"
462
- },
463
- { status: import_router2.statusCode.UNAUTHORIZED }
464
- );
465
- }
466
- if (error instanceof InvalidRedirectToError) {
467
- const { type, message } = error;
468
- return AuraResponse.json(
469
- {
470
- error: type,
471
- error_description: message
472
- },
473
- { status: import_router2.statusCode.BAD_REQUEST }
474
- );
475
- }
476
- return AuraResponse.json(
477
- {
478
- error: "invalid_session_token",
479
- error_description: "The provided sessionToken is invalid or has already expired"
480
- },
481
- { status: import_router2.statusCode.UNAUTHORIZED }
482
- );
315
+ const session = headers.getCookie(cookies.sessionToken.name);
316
+ const csrfToken = headers.getCookie(cookies.csrfToken.name);
317
+ const header = headers.getHeader("X-CSRF-Token");
318
+ if (!session) {
319
+ throw new AuthSecurityError("SESSION_TOKEN_MISSING", "The sessionToken is missing.");
320
+ }
321
+ if (!csrfToken) {
322
+ throw new AuthSecurityError("CSRF_TOKEN_MISSING", "The CSRF token is missing.");
483
323
  }
324
+ if (!header) {
325
+ throw new AuthSecurityError("CSRF_TOKEN_MISSING", "The CSRF header is missing.");
326
+ }
327
+ await verifyCSRF(jose, csrfToken, header);
328
+ await jose.decodeJWT(session);
329
+ const normalizedOriginPath = getNormalizedOriginPath(request.url);
330
+ const location = createRedirectTo(
331
+ new Request(normalizedOriginPath, {
332
+ headers: headers.toHeaders()
333
+ }),
334
+ redirectTo
335
+ );
336
+ const headersList = new import_router2.HeadersBuilder(cacheControl).setHeader("Location", location).setCookie(cookies.csrfToken.name, "", expiredCookieAttributes).setCookie(cookies.sessionToken.name, "", expiredCookieAttributes).toHeaders();
337
+ return Response.json({ message: "Signed out successfully" }, { status: import_router2.statusCode.ACCEPTED, headers: headersList });
484
338
  },
485
339
  config
486
340
  );
@@ -1,15 +1,14 @@
1
1
  import {
2
2
  signOutAction
3
- } from "../../chunk-SJPDVKUS.js";
4
- import "../../chunk-CAKJT3KS.js";
5
- import "../../chunk-ZV4BH47P.js";
6
- import "../../chunk-6SM22VVJ.js";
3
+ } from "../../chunk-A3N4PVAT.js";
4
+ import "../../chunk-N4SX7TZT.js";
5
+ import "../../chunk-W6LG7BFW.js";
7
6
  import "../../chunk-STHEPPUZ.js";
8
- import "../../chunk-GZU3RBTB.js";
9
- import "../../chunk-256KIVJL.js";
10
- import "../../chunk-FJUDBLCP.js";
11
- import "../../chunk-JAPMIE6S.js";
12
- import "../../chunk-HMRKN75I.js";
7
+ import "../../chunk-N2APGLXA.js";
8
+ import "../../chunk-CXLATHS5.js";
9
+ import "../../chunk-EIL2FPSS.js";
10
+ import "../../chunk-RRLIF4PQ.js";
11
+ import "../../chunk-YRCB5FLE.js";
13
12
  export {
14
13
  signOutAction
15
14
  };
package/dist/assert.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var assert_exports = {};
22
22
  __export(assert_exports, {
23
23
  isFalsy: () => isFalsy,
24
+ isJWTPayloadWithToken: () => isJWTPayloadWithToken,
24
25
  isRequest: () => isRequest,
25
26
  isValidURL: () => isValidURL
26
27
  });
@@ -36,9 +37,13 @@ var isValidURL = (value) => {
36
37
  const regex = /^https?:\/\/(?:[a-zA-Z0-9._-]+|localhost|\[[0-9a-fA-F:]+\])(?::\d{1,5})?(?:\/[a-zA-Z0-9._~!$&'()*+,;=:@-]*)*\/?$/;
37
38
  return regex.test(value);
38
39
  };
40
+ var isJWTPayloadWithToken = (payload) => {
41
+ return typeof payload === "object" && payload !== null && "token" in payload && typeof payload?.token === "string";
42
+ };
39
43
  // Annotate the CommonJS export names for ESM import in node:
40
44
  0 && (module.exports = {
41
45
  isFalsy,
46
+ isJWTPayloadWithToken,
42
47
  isRequest,
43
48
  isValidURL
44
49
  });
package/dist/assert.d.ts CHANGED
@@ -1,5 +1,14 @@
1
+ import { J as JWTPayloadWithToken } from './index-DkaLJFn8.js';
2
+ import 'zod';
3
+ import './schemas.js';
4
+ import '@aura-stack/router/cookie';
5
+ import '@aura-stack/jose';
6
+ import '@aura-stack/jose/jose';
7
+ import './@types/utility.js';
8
+
1
9
  declare const isFalsy: (value: unknown) => boolean;
2
10
  declare const isRequest: (value: unknown) => value is Request;
3
11
  declare const isValidURL: (value: string) => boolean;
12
+ declare const isJWTPayloadWithToken: (payload: unknown) => payload is JWTPayloadWithToken;
4
13
 
5
- export { isFalsy, isRequest, isValidURL };
14
+ export { isFalsy, isJWTPayloadWithToken, isRequest, isValidURL };
package/dist/assert.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import {
2
2
  isFalsy,
3
+ isJWTPayloadWithToken,
3
4
  isRequest,
4
5
  isValidURL
5
- } from "./chunk-6SM22VVJ.js";
6
+ } from "./chunk-EIL2FPSS.js";
6
7
  export {
7
8
  isFalsy,
9
+ isJWTPayloadWithToken,
8
10
  isRequest,
9
11
  isValidURL
10
12
  };