@aura-stack/auth 0.4.0-rc.5 → 0.4.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 (143) hide show
  1. package/dist/@types/index.d.ts +4 -3
  2. package/dist/@types/router.d.cjs +0 -17
  3. package/dist/@types/router.d.d.ts +3 -2
  4. package/dist/@types/router.d.js +0 -1
  5. package/dist/actions/callback/access-token.cjs +40 -25
  6. package/dist/actions/callback/access-token.d.ts +4 -3
  7. package/dist/actions/callback/access-token.js +3 -4
  8. package/dist/actions/callback/callback.cjs +287 -77
  9. package/dist/actions/callback/callback.d.ts +5 -26
  10. package/dist/actions/callback/callback.js +13 -10
  11. package/dist/actions/callback/userinfo.cjs +68 -7
  12. package/dist/actions/callback/userinfo.d.ts +4 -3
  13. package/dist/actions/callback/userinfo.js +8 -6
  14. package/dist/actions/csrfToken/csrfToken.cjs +63 -4
  15. package/dist/actions/csrfToken/csrfToken.d.ts +1 -3
  16. package/dist/actions/csrfToken/csrfToken.js +8 -6
  17. package/dist/actions/index.cjs +400 -175
  18. package/dist/actions/index.d.ts +3 -2
  19. package/dist/actions/index.js +21 -19
  20. package/dist/actions/session/session.cjs +40 -11
  21. package/dist/actions/session/session.d.ts +1 -3
  22. package/dist/actions/session/session.js +4 -4
  23. package/dist/actions/signIn/authorization.cjs +171 -132
  24. package/dist/actions/signIn/authorization.d.ts +21 -11
  25. package/dist/actions/signIn/authorization.js +8 -6
  26. package/dist/actions/signIn/signIn.cjs +220 -113
  27. package/dist/actions/signIn/signIn.d.ts +5 -25
  28. package/dist/actions/signIn/signIn.js +9 -7
  29. package/dist/actions/signOut/signOut.cjs +268 -119
  30. package/dist/actions/signOut/signOut.d.ts +1 -9
  31. package/dist/actions/signOut/signOut.js +10 -8
  32. package/dist/assert.cjs +117 -5
  33. package/dist/assert.d.ts +22 -3
  34. package/dist/assert.js +17 -3
  35. package/dist/chunk-4EKY7655.js +123 -0
  36. package/dist/chunk-4MYWAOLG.js +31 -0
  37. package/dist/chunk-4YHJ4IEQ.js +25 -0
  38. package/dist/chunk-54CZPKR4.js +25 -0
  39. package/dist/chunk-5LZ7TOM3.js +25 -0
  40. package/dist/{chunk-W6LG7BFW.js → chunk-5W4BRQYG.js} +24 -20
  41. package/dist/chunk-6MXFPFR3.js +143 -0
  42. package/dist/{chunk-3EUWD5BB.js → chunk-7QF22LHP.js} +13 -9
  43. package/dist/chunk-ALG3GIV4.js +95 -0
  44. package/dist/chunk-E6G5YCI6.js +25 -0
  45. package/dist/chunk-EBAMFRB7.js +34 -0
  46. package/dist/chunk-EEE7UM5T.js +25 -0
  47. package/dist/{chunk-TLE4PXY3.js → chunk-FRJFWTOY.js} +38 -7
  48. package/dist/chunk-FW4W3REU.js +25 -0
  49. package/dist/{chunk-HT4YLL7N.js → chunk-ICAZ4OVS.js} +10 -8
  50. package/dist/chunk-IPKO6UQN.js +25 -0
  51. package/dist/{chunk-YRCB5FLE.js → chunk-KJBAQZX2.js} +13 -0
  52. package/dist/chunk-KMMAZFSJ.js +25 -0
  53. package/dist/chunk-LDU7A2JE.js +25 -0
  54. package/dist/{chunk-N2APGLXA.js → chunk-NUDITUKX.js} +18 -16
  55. package/dist/chunk-OVHNRULD.js +33 -0
  56. package/dist/{chunk-JVFTCTTE.js → chunk-PHFH2MGS.js} +12 -9
  57. package/dist/chunk-QQVSRXGX.js +149 -0
  58. package/dist/chunk-TM5IPSNF.js +113 -0
  59. package/dist/{chunk-GA2SMTJO.js → chunk-TZB6MUXN.js} +33 -13
  60. package/dist/chunk-VNCNJKS2.js +267 -0
  61. package/dist/{chunk-IVET23KF.js → chunk-XGLBNXL4.js} +31 -14
  62. package/dist/chunk-XUP6KKNG.js +106 -0
  63. package/dist/cookie.cjs +24 -20
  64. package/dist/cookie.d.ts +4 -3
  65. package/dist/cookie.js +1 -1
  66. package/dist/env.cjs +56 -0
  67. package/dist/env.d.ts +7 -0
  68. package/dist/env.js +6 -0
  69. package/dist/errors.d.ts +4 -3
  70. package/dist/headers.cjs +28 -2
  71. package/dist/headers.d.ts +25 -1
  72. package/dist/headers.js +9 -3
  73. package/dist/{index-B8jeIElf.d.ts → index-CSyIJmCM.d.ts} +373 -45
  74. package/dist/index.cjs +1128 -483
  75. package/dist/index.d.ts +7 -67
  76. package/dist/index.js +83 -42
  77. package/dist/jose.cjs +62 -25
  78. package/dist/jose.d.ts +7 -5
  79. package/dist/jose.js +8 -6
  80. package/dist/logger.cjs +292 -0
  81. package/dist/logger.d.ts +8 -0
  82. package/dist/logger.js +8 -0
  83. package/dist/oauth/bitbucket.cjs +19 -15
  84. package/dist/oauth/bitbucket.d.ts +3 -2
  85. package/dist/oauth/bitbucket.js +1 -1
  86. package/dist/oauth/discord.cjs +27 -24
  87. package/dist/oauth/discord.d.ts +3 -2
  88. package/dist/oauth/discord.js +1 -1
  89. package/dist/oauth/figma.cjs +19 -16
  90. package/dist/oauth/figma.d.ts +3 -2
  91. package/dist/oauth/figma.js +1 -1
  92. package/dist/oauth/github.cjs +19 -8
  93. package/dist/oauth/github.d.ts +3 -2
  94. package/dist/oauth/github.js +1 -1
  95. package/dist/oauth/gitlab.cjs +19 -16
  96. package/dist/oauth/gitlab.d.ts +3 -2
  97. package/dist/oauth/gitlab.js +1 -1
  98. package/dist/oauth/index.cjs +266 -166
  99. package/dist/oauth/index.d.ts +3 -2
  100. package/dist/oauth/index.js +22 -21
  101. package/dist/oauth/mailchimp.cjs +19 -16
  102. package/dist/oauth/mailchimp.d.ts +3 -2
  103. package/dist/oauth/mailchimp.js +1 -1
  104. package/dist/oauth/pinterest.cjs +19 -16
  105. package/dist/oauth/pinterest.d.ts +3 -2
  106. package/dist/oauth/pinterest.js +1 -1
  107. package/dist/oauth/spotify.cjs +19 -16
  108. package/dist/oauth/spotify.d.ts +3 -2
  109. package/dist/oauth/spotify.js +1 -1
  110. package/dist/oauth/strava.cjs +19 -16
  111. package/dist/oauth/strava.d.ts +3 -2
  112. package/dist/oauth/strava.js +1 -1
  113. package/dist/oauth/x.cjs +19 -16
  114. package/dist/oauth/x.d.ts +3 -2
  115. package/dist/oauth/x.js +1 -1
  116. package/dist/schemas.cjs +16 -2
  117. package/dist/schemas.d.ts +17 -1
  118. package/dist/schemas.js +5 -3
  119. package/dist/secure.cjs +58 -16
  120. package/dist/secure.d.ts +4 -10
  121. package/dist/secure.js +5 -5
  122. package/dist/utils.cjs +94 -87
  123. package/dist/utils.d.ts +9 -39
  124. package/dist/utils.js +11 -9
  125. package/package.json +3 -4
  126. package/dist/chunk-42XB3YCW.js +0 -22
  127. package/dist/chunk-6R2YZ4AC.js +0 -22
  128. package/dist/chunk-A3N4PVAT.js +0 -70
  129. package/dist/chunk-B737EUJV.js +0 -22
  130. package/dist/chunk-CXLATHS5.js +0 -143
  131. package/dist/chunk-DIVDFNAP.js +0 -0
  132. package/dist/chunk-E3OXBRYF.js +0 -22
  133. package/dist/chunk-EIL2FPSS.js +0 -22
  134. package/dist/chunk-EMKJA2GJ.js +0 -89
  135. package/dist/chunk-FIPU4MLT.js +0 -21
  136. package/dist/chunk-FKRDCWBF.js +0 -22
  137. package/dist/chunk-HP34YGGJ.js +0 -22
  138. package/dist/chunk-IKHPGFCW.js +0 -14
  139. package/dist/chunk-IUYZQTJV.js +0 -30
  140. package/dist/chunk-KRNOMBXQ.js +0 -22
  141. package/dist/chunk-KSWLO5ZU.js +0 -102
  142. package/dist/chunk-N4SX7TZT.js +0 -96
  143. package/dist/chunk-STHEPPUZ.js +0 -11
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/actions/signOut/signOut.ts
@@ -36,13 +26,20 @@ module.exports = __toCommonJS(signOut_exports);
36
26
  var import_zod2 = require("zod");
37
27
  var import_router2 = require("@aura-stack/router");
38
28
 
39
- // src/secure.ts
40
- var import_crypto = __toESM(require("crypto"), 1);
41
-
42
29
  // src/utils.ts
43
30
  var import_router = require("@aura-stack/router");
44
31
 
45
32
  // src/errors.ts
33
+ var AuthInternalError = class extends Error {
34
+ type = "AUTH_INTERNAL_ERROR";
35
+ code;
36
+ constructor(code, message, options2) {
37
+ super(message, options2);
38
+ this.code = code;
39
+ this.name = new.target.name;
40
+ Error.captureStackTrace(this, new.target);
41
+ }
42
+ };
46
43
  var AuthSecurityError = class extends Error {
47
44
  type = "AUTH_SECURITY_ERROR";
48
45
  code;
@@ -53,86 +50,180 @@ var AuthSecurityError = class extends Error {
53
50
  Error.captureStackTrace(this, new.target);
54
51
  }
55
52
  };
56
- var isAuthSecurityError = (error) => {
57
- return error instanceof AuthSecurityError;
58
- };
59
53
 
60
54
  // src/utils.ts
61
55
  var equals = (a, b) => {
62
56
  if (a === null || b === null || a === void 0 || b === void 0) return false;
63
57
  return a === b;
64
58
  };
65
- var sanitizeURL = (url) => {
66
- try {
67
- let decodedURL = decodeURIComponent(url).trim();
68
- const protocolMatch = decodedURL.match(/^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)/);
69
- let protocol = "";
70
- let rest = decodedURL;
71
- if (protocolMatch) {
72
- protocol = protocolMatch[1];
73
- rest = decodedURL.slice(protocol.length);
74
- const slashIndex = rest.indexOf("/");
75
- if (slashIndex === -1) {
76
- return protocol + rest;
77
- }
78
- const domain = rest.slice(0, slashIndex);
79
- let path = rest.slice(slashIndex).replace(/\/\.\.\//g, "/").replace(/\/\.\.$/, "").replace(/\.{2,}/g, "").replace(/\/{2,}/g, "/");
80
- if (path !== "/" && path.endsWith("/")) {
81
- path = path.replace(/\/+$/, "/");
82
- } else if (path !== "/") {
83
- path = path.replace(/\/+$/, "");
84
- }
85
- return protocol + domain + path;
86
- }
87
- let sanitized = decodedURL.replace(/\/\.\.\//g, "/").replace(/\/\.\.$/, "").replace(/\.{2,}/g, "").replace(/\/{2,}/g, "/");
88
- if (sanitized !== "/" && sanitized.endsWith("/")) {
89
- sanitized = sanitized.replace(/\/+$/, "/");
90
- } else if (sanitized !== "/") {
91
- sanitized = sanitized.replace(/\/+$/, "");
92
- }
93
- return sanitized;
94
- } catch {
95
- return url.trim();
96
- }
59
+ var getBaseURL = (request) => {
60
+ const url = new URL(request.url);
61
+ return `${url.origin}${url.pathname}`;
97
62
  };
98
- var getNormalizedOriginPath = (path) => {
99
- try {
100
- const url = new URL(path);
101
- url.hash = "";
102
- url.search = "";
103
- return `${url.origin}${url.pathname}`;
104
- } catch {
105
- return sanitizeURL(path);
63
+ var extractPath = (url) => {
64
+ const pathRegex = /^https?:\/\/[a-zA-Z0-9_\-\.]+(:\d+)?(\/.*)$/;
65
+ const match = url.match(pathRegex);
66
+ return match && match[2] ? match[2] : "/";
67
+ };
68
+ var getErrorName = (error) => {
69
+ if (error instanceof Error) {
70
+ return error.name;
106
71
  }
72
+ return typeof error === "string" ? error : "UnknownError";
107
73
  };
108
74
 
109
75
  // src/assert.ts
76
+ var import_crypto = require("crypto");
77
+ var unsafeChars = [
78
+ "<",
79
+ ">",
80
+ '"',
81
+ "`",
82
+ " ",
83
+ "\r",
84
+ "\n",
85
+ " ",
86
+ "\\",
87
+ "%2F",
88
+ "%5C",
89
+ "%2f",
90
+ "%5c",
91
+ "\r\n",
92
+ "%0A",
93
+ "%0D",
94
+ "%0a",
95
+ "%0d",
96
+ "..",
97
+ "//",
98
+ "///",
99
+ "...",
100
+ "%20",
101
+ "\0"
102
+ ];
110
103
  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);
104
+ if (!new RegExp(/^https?:\/\/[^/]/).test(value)) {
105
+ return false;
106
+ }
107
+ const match = value.match(/^(https?:\/\/)(.*)$/);
108
+ if (!match) return false;
109
+ const rest = match[2];
110
+ for (const char of unsafeChars) {
111
+ if (rest.includes(char)) return false;
112
+ }
113
+ const regex = /^https?:\/\/(?:[a-zA-Z0-9._-]+|localhost|\[[0-9a-fA-F:]+\])(?::\d{1,5})?(?:\/[a-zA-Z0-9._~!$&'()?#*+,;=:@-]*)*\/?$/;
114
+ return regex.test(match[0]);
114
115
  };
115
116
  var isJWTPayloadWithToken = (payload) => {
116
117
  return typeof payload === "object" && payload !== null && "token" in payload && typeof payload?.token === "string";
117
118
  };
119
+ var isRelativeURL = (value) => {
120
+ if (value.length > 100) return false;
121
+ for (const char of unsafeChars) {
122
+ if (value.includes(char)) return false;
123
+ }
124
+ const regex = /^\/[a-zA-Z0-9\-_\/.?&=#]*\/?$/;
125
+ return regex.test(value);
126
+ };
127
+ var isSameOrigin = (origin, expected) => {
128
+ const originURL = new URL(origin);
129
+ const expectedURL = new URL(expected);
130
+ return equals(originURL.origin, expectedURL.origin);
131
+ };
132
+ var patternToRegex = (pattern) => {
133
+ try {
134
+ if (pattern.length > 2048) return null;
135
+ pattern = pattern.replace(/\\/g, "");
136
+ const match = pattern.match(/^(https?):\/\/([a-zA-Z0-9.*-]{1,253})(?::(\d{1,5}|\*))?(?:\/.*)?$/);
137
+ if (!match) return null;
138
+ const [, protocol, host, port] = match;
139
+ const hasWildcard = host.includes("*");
140
+ if (hasWildcard && !host.startsWith("*.")) return null;
141
+ if (hasWildcard && host.slice(2).includes("*")) return null;
142
+ const domain = hasWildcard ? host.slice(2) : host;
143
+ const escapedDomain = domain.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
144
+ const hostRegex = hasWildcard ? `[^.]+\\.${escapedDomain}` : escapedDomain;
145
+ const portRegex = port === "*" ? ":\\d{1,5}" : port ? `:${port}` : "";
146
+ return new RegExp(`^${protocol}:\\/\\/${hostRegex}${portRegex}$`);
147
+ } catch {
148
+ return null;
149
+ }
150
+ };
151
+ var isTrustedOrigin = (url, trustedOrigins) => {
152
+ if (!isValidURL(url) || trustedOrigins.length === 0) return false;
153
+ try {
154
+ const urlOrigin = new URL(url).origin;
155
+ for (const pattern of trustedOrigins) {
156
+ const regex = patternToRegex(pattern);
157
+ if (regex?.test(urlOrigin)) return true;
158
+ try {
159
+ if (isValidURL(pattern) && equals(new URL(pattern).origin, urlOrigin)) return true;
160
+ } catch {
161
+ }
162
+ }
163
+ } catch {
164
+ }
165
+ return false;
166
+ };
167
+ var safeEquals = (a, b) => {
168
+ const bufferA = Buffer.from(a);
169
+ const bufferB = Buffer.from(b);
170
+ if (bufferA.length !== bufferB.length) {
171
+ return false;
172
+ }
173
+ return (0, import_crypto.timingSafeEqual)(bufferA, bufferB);
174
+ };
175
+
176
+ // src/env.ts
177
+ var import_meta = {};
178
+ var env = new Proxy({}, {
179
+ get(_, prop) {
180
+ if (typeof prop !== "string") return void 0;
181
+ const hasProperty = (process2) => {
182
+ return process2 && Object.prototype.hasOwnProperty.call(process2, prop);
183
+ };
184
+ try {
185
+ if (typeof process !== "undefined" && hasProperty(process.env)) {
186
+ return process.env[prop];
187
+ }
188
+ if (typeof import_meta !== "undefined" && hasProperty(import_meta.env)) {
189
+ return import_meta.env[prop];
190
+ }
191
+ if (typeof Deno !== "undefined" && Deno.env?.get) {
192
+ return Deno.env.get(prop);
193
+ }
194
+ if (typeof Bun !== "undefined" && hasProperty(Bun.env)) {
195
+ return Bun.env[prop];
196
+ }
197
+ const globalValue = globalThis[prop];
198
+ return typeof globalValue === "string" ? globalValue : void 0;
199
+ } catch {
200
+ return void 0;
201
+ }
202
+ }
203
+ });
204
+
205
+ // src/jose.ts
206
+ var import_jose = require("@aura-stack/jose");
207
+ var jwtVerificationOptions = {
208
+ algorithms: ["HS256"],
209
+ typ: "JWT"
210
+ };
118
211
 
119
212
  // src/secure.ts
120
213
  var verifyCSRF = async (jose, cookie, header) => {
121
214
  try {
122
- const cookiePayload = await jose.verifyJWS(cookie);
123
- const headerPayload = await jose.verifyJWS(header);
215
+ const cookiePayload = await jose.verifyJWS(cookie, jwtVerificationOptions);
216
+ const headerPayload = await jose.verifyJWS(header, jwtVerificationOptions);
124
217
  if (!isJWTPayloadWithToken(cookiePayload)) {
125
218
  throw new AuthSecurityError("CSRF_TOKEN_INVALID", "Cookie payload missing token field.");
126
219
  }
127
220
  if (!isJWTPayloadWithToken(headerPayload)) {
128
221
  throw new AuthSecurityError("CSRF_TOKEN_INVALID", "Header payload missing token field.");
129
222
  }
130
- const cookieBuffer = Buffer.from(cookiePayload.token);
131
- const headerBuffer = Buffer.from(headerPayload.token);
132
- if (!equals(headerBuffer.length, cookieBuffer.length)) {
223
+ if (!equals(cookiePayload.token.length, headerPayload.token.length)) {
133
224
  throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
134
225
  }
135
- if (!import_crypto.default.timingSafeEqual(cookieBuffer, headerBuffer)) {
226
+ if (!safeEquals(cookiePayload.token, headerPayload.token)) {
136
227
  throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
137
228
  }
138
229
  return true;
@@ -148,6 +239,26 @@ var cacheControl = {
148
239
  Expires: "0",
149
240
  Vary: "Cookie"
150
241
  };
242
+ var contentSecurityPolicy = {
243
+ "Content-Security-Policy": [
244
+ "default-src 'none'",
245
+ "script-src 'self'",
246
+ "frame-src 'none'",
247
+ "object-src 'none'",
248
+ "frame-ancestors 'none'",
249
+ "base-uri 'none'"
250
+ ].join("; ")
251
+ };
252
+ var secureHeaders = {
253
+ "X-Content-Type-Options": "nosniff",
254
+ "X-Frame-Options": "DENY",
255
+ "Referrer-Policy": "strict-origin-when-cross-origin"
256
+ };
257
+ var secureApiHeaders = {
258
+ ...cacheControl,
259
+ ...contentSecurityPolicy,
260
+ ...secureHeaders
261
+ };
151
262
 
152
263
  // src/cookie.ts
153
264
  var import_cookie = require("@aura-stack/router/cookie");
@@ -166,11 +277,24 @@ var oauthCookieOptions = {
166
277
  var expiredCookieAttributes = {
167
278
  ...defaultCookieOptions,
168
279
  expires: /* @__PURE__ */ new Date(0),
169
- maxAge: 0
280
+ maxAge: 0,
281
+ secure: true
170
282
  };
171
283
 
172
284
  // src/schemas.ts
173
285
  var import_zod = require("zod");
286
+ var OAuthProviderCredentialsSchema = (0, import_zod.object)({
287
+ id: (0, import_zod.string)(),
288
+ name: (0, import_zod.string)(),
289
+ authorizeURL: (0, import_zod.string)().url(),
290
+ accessToken: (0, import_zod.string)().url(),
291
+ scope: (0, import_zod.string)(),
292
+ userInfo: (0, import_zod.string)().url(),
293
+ responseType: (0, import_zod.enum)(["code", "token", "id_token"]),
294
+ clientId: (0, import_zod.string)(),
295
+ clientSecret: (0, import_zod.string)(),
296
+ profile: import_zod.z.function().optional()
297
+ });
174
298
  var OAuthProviderConfigSchema = (0, import_zod.object)({
175
299
  authorizeURL: (0, import_zod.string)().url(),
176
300
  accessToken: (0, import_zod.string)().url(),
@@ -238,58 +362,59 @@ var OAuthEnvSchema = (0, import_zod.object)({
238
362
  });
239
363
 
240
364
  // src/actions/signIn/authorization.ts
241
- var getOriginURL = (request, trustedProxyHeaders) => {
365
+ var getTrustedOrigins = async (request, trustedOrigins) => {
366
+ if (!trustedOrigins) return [];
367
+ const raw = typeof trustedOrigins === "function" ? await trustedOrigins(request) : trustedOrigins;
368
+ return Array.isArray(raw) ? raw : typeof raw === "string" ? [raw] : [];
369
+ };
370
+ var getOriginURL = async (request, context) => {
242
371
  const headers = request.headers;
243
- if (trustedProxyHeaders) {
244
- const protocol = headers.get("X-Forwarded-Proto") ?? headers.get("Forwarded")?.match(/proto=([^;]+)/i)?.[1] ?? "http";
245
- const host = headers.get("X-Forwarded-Host") ?? headers.get("Host") ?? headers.get("Forwarded")?.match(/host=([^;]+)/i)?.[1] ?? null;
246
- return new URL(`${protocol}://${host}${getNormalizedOriginPath(new URL(request.url).pathname)}`);
247
- } else {
248
- return new URL(getNormalizedOriginPath(request.url));
372
+ let origin = new URL(request.url).origin;
373
+ const trustedOrigins = await getTrustedOrigins(request, context?.trustedOrigins);
374
+ trustedOrigins.push(origin);
375
+ if (context?.trustedProxyHeaders) {
376
+ const protocol = headers.get("Forwarded")?.match(/proto=([^;]+)/i)?.[1] ?? headers.get("X-Forwarded-Proto") ?? "http";
377
+ const host = headers.get("Host") ?? headers.get("Forwarded")?.match(/host=([^;]+)/i)?.[1] ?? headers.get("X-Forwarded-Host") ?? null;
378
+ origin = `${protocol}://${host}`;
379
+ }
380
+ if (!isTrustedOrigin(origin, trustedOrigins)) {
381
+ context?.logger?.log("UNTRUSTED_ORIGIN", { structuredData: { origin } });
382
+ throw new AuthInternalError("UNTRUSTED_ORIGIN", "The constructed origin URL is not trusted.");
249
383
  }
384
+ return origin;
250
385
  };
251
- var createRedirectTo = (request, redirectTo, trustedProxyHeaders) => {
386
+ var createRedirectTo = async (request, redirectTo, context) => {
252
387
  try {
253
388
  const headers = request.headers;
254
- const origin = headers.get("Origin");
255
- const referer = headers.get("Referer");
256
- let hostedURL = getOriginURL(request, trustedProxyHeaders);
257
- if (redirectTo) {
258
- if (redirectTo.startsWith("/")) {
259
- return sanitizeURL(redirectTo);
260
- }
261
- const redirectToURL = new URL(sanitizeURL(getNormalizedOriginPath(redirectTo)));
262
- if (!isValidURL(redirectTo) || !equals(redirectToURL.origin, hostedURL.origin)) {
263
- throw new AuthSecurityError(
264
- "POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
265
- "The redirectTo parameter does not match the hosted origin."
266
- );
267
- }
268
- return sanitizeURL(redirectToURL.pathname);
269
- }
270
- if (referer) {
271
- const refererURL = new URL(sanitizeURL(referer));
272
- if (!isValidURL(referer) || !equals(refererURL.origin, hostedURL.origin)) {
273
- throw new AuthSecurityError(
274
- "POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
275
- "The referer of the request does not match the hosted origin."
276
- );
389
+ const requestOrigin = await getOriginURL(request, context);
390
+ const origins = await getTrustedOrigins(request, context?.trustedOrigins);
391
+ const validateURL = (url) => {
392
+ if (!isRelativeURL(url) && !isValidURL(url)) return "/";
393
+ if (isRelativeURL(url)) return url;
394
+ if (origins.length > 0) {
395
+ if (isTrustedOrigin(url, origins)) {
396
+ const urlOrigin = new URL(url).origin;
397
+ for (const pattern of origins) {
398
+ const regex = patternToRegex(pattern);
399
+ if (regex?.test(urlOrigin)) {
400
+ return isSameOrigin(url, request.url) ? extractPath(url) : url;
401
+ }
402
+ if (isValidURL(pattern) && equals(new URL(pattern).origin, urlOrigin)) return url;
403
+ }
404
+ }
405
+ context?.logger?.log("OPEN_REDIRECT_ATTACK");
406
+ return "/";
277
407
  }
278
- return sanitizeURL(refererURL.pathname);
279
- }
280
- if (origin) {
281
- const originURL = new URL(sanitizeURL(getNormalizedOriginPath(origin)));
282
- if (!isValidURL(origin) || !equals(originURL.origin, hostedURL.origin)) {
283
- throw new AuthSecurityError("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", "Invalid origin (potential CSRF).");
408
+ if (isSameOrigin(url, requestOrigin)) {
409
+ return extractPath(url);
284
410
  }
285
- return sanitizeURL(originURL.pathname);
286
- }
287
- return "/";
411
+ context?.logger?.log("OPEN_REDIRECT_ATTACK");
412
+ return "/";
413
+ };
414
+ return validateURL(redirectTo ?? headers.get("Referer") ?? headers.get("Origin") ?? "/");
288
415
  } catch (error) {
289
- if (isAuthSecurityError(error)) {
290
- throw error;
291
- }
292
- throw new AuthSecurityError("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", "Invalid origin (potential CSRF).");
416
+ context?.logger?.log("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED");
417
+ return "/";
293
418
  }
294
419
  };
295
420
 
@@ -310,30 +435,54 @@ var signOutAction = (0, import_router2.createEndpoint)(
310
435
  request,
311
436
  headers,
312
437
  searchParams: { redirectTo },
313
- context: { jose, cookies }
438
+ context
314
439
  } = ctx;
440
+ const { jose, cookies, logger } = context;
315
441
  const session = headers.getCookie(cookies.sessionToken.name);
316
442
  const csrfToken = headers.getCookie(cookies.csrfToken.name);
317
443
  const header = headers.getHeader("X-CSRF-Token");
444
+ logger?.log("SIGN_OUT_ATTEMPT", {
445
+ structuredData: {
446
+ has_session: Boolean(session),
447
+ has_csrf_token: Boolean(csrfToken),
448
+ has_csrf_header: Boolean(header)
449
+ }
450
+ });
318
451
  if (!session) {
452
+ logger?.log("SESSION_TOKEN_MISSING");
319
453
  throw new AuthSecurityError("SESSION_TOKEN_MISSING", "The sessionToken is missing.");
320
454
  }
321
455
  if (!csrfToken) {
456
+ logger?.log("CSRF_TOKEN_MISSING");
322
457
  throw new AuthSecurityError("CSRF_TOKEN_MISSING", "The CSRF token is missing.");
323
458
  }
324
459
  if (!header) {
325
- throw new AuthSecurityError("CSRF_TOKEN_MISSING", "The CSRF header is missing.");
460
+ logger?.log("CSRF_HEADER_MISSING");
461
+ throw new AuthSecurityError("CSRF_HEADER_MISSING", "The CSRF header is missing.");
462
+ }
463
+ try {
464
+ await verifyCSRF(jose, csrfToken, header);
465
+ } catch (error) {
466
+ logger?.log("CSRF_TOKEN_INVALID", { structuredData: { error_type: getErrorName(error) } });
467
+ throw new AuthSecurityError("CSRF_TOKEN_INVALID", "CSRF token verification failed");
468
+ }
469
+ logger?.log("SIGN_OUT_CSRF_VERIFIED");
470
+ try {
471
+ await jose.decodeJWT(session);
472
+ logger?.log("SIGN_OUT_SUCCESS");
473
+ } catch (error) {
474
+ logger?.log("INVALID_JWT_TOKEN", { structuredData: { error_type: getErrorName(error) } });
326
475
  }
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, {
476
+ const baseURL = getBaseURL(request);
477
+ const location = await createRedirectTo(
478
+ new Request(baseURL, {
332
479
  headers: headers.toHeaders()
333
480
  }),
334
- redirectTo
481
+ redirectTo,
482
+ context
335
483
  );
336
- const headersList = new import_router2.HeadersBuilder(cacheControl).setHeader("Location", location).setCookie(cookies.csrfToken.name, "", expiredCookieAttributes).setCookie(cookies.sessionToken.name, "", expiredCookieAttributes).toHeaders();
484
+ logger?.log("SIGN_OUT_REDIRECT", { structuredData: { location } });
485
+ const headersList = new import_router2.HeadersBuilder(secureApiHeaders).setHeader("Location", location).setCookie(cookies.csrfToken.name, "", expiredCookieAttributes).setCookie(cookies.sessionToken.name, "", expiredCookieAttributes).toHeaders();
337
486
  return Response.json({ message: "Signed out successfully" }, { status: import_router2.statusCode.ACCEPTED, headers: headersList });
338
487
  },
339
488
  config
@@ -1,16 +1,8 @@
1
1
  import * as _aura_stack_router from '@aura-stack/router';
2
- import { z } from 'zod';
3
2
 
4
3
  /**
5
4
  * @see https://datatracker.ietf.org/doc/html/rfc7009
6
5
  */
7
- declare const signOutAction: _aura_stack_router.RouteEndpoint<"POST", "/signOut", {
8
- schemas?: {
9
- searchParams: z.ZodObject<{
10
- token_type_hint: z.ZodLiteral<"session_token">;
11
- redirectTo: z.ZodOptional<z.ZodString>;
12
- }, z.core.$strip>;
13
- } | undefined;
14
- }>;
6
+ declare const signOutAction: _aura_stack_router.RouteEndpoint<"POST", "/signOut", {}>;
15
7
 
16
8
  export { signOutAction };
@@ -1,14 +1,16 @@
1
1
  import {
2
2
  signOutAction
3
- } from "../../chunk-A3N4PVAT.js";
4
- import "../../chunk-N4SX7TZT.js";
5
- import "../../chunk-W6LG7BFW.js";
6
- import "../../chunk-STHEPPUZ.js";
7
- import "../../chunk-N2APGLXA.js";
8
- import "../../chunk-CXLATHS5.js";
9
- import "../../chunk-EIL2FPSS.js";
3
+ } from "../../chunk-ALG3GIV4.js";
4
+ import "../../chunk-XUP6KKNG.js";
5
+ import "../../chunk-KJBAQZX2.js";
6
+ import "../../chunk-NUDITUKX.js";
7
+ import "../../chunk-4EKY7655.js";
8
+ import "../../chunk-QQVSRXGX.js";
9
+ import "../../chunk-5W4BRQYG.js";
10
+ import "../../chunk-EBAMFRB7.js";
11
+ import "../../chunk-FRJFWTOY.js";
12
+ import "../../chunk-4MYWAOLG.js";
10
13
  import "../../chunk-RRLIF4PQ.js";
11
- import "../../chunk-YRCB5FLE.js";
12
14
  export {
13
15
  signOutAction
14
16
  };