@aura-stack/auth 0.4.0-rc.4 → 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-DkaLJFn8.d.ts → index-CSyIJmCM.d.ts} +373 -45
  74. package/dist/index.cjs +1128 -483
  75. package/dist/index.d.ts +6 -10
  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
@@ -4,10 +4,11 @@ export { sessionAction } from './session/session.js';
4
4
  export { signOutAction } from './signOut/signOut.js';
5
5
  export { csrfTokenAction } from './csrfToken/csrfToken.js';
6
6
  import '@aura-stack/router';
7
+ import '../index-CSyIJmCM.js';
7
8
  import 'zod';
8
- import '../index-DkaLJFn8.js';
9
9
  import '../schemas.js';
10
- import '@aura-stack/router/cookie';
10
+ import '../jose.js';
11
11
  import '@aura-stack/jose';
12
12
  import '@aura-stack/jose/jose';
13
+ import '@aura-stack/router/cookie';
13
14
  import '../@types/utility.js';
@@ -1,30 +1,32 @@
1
1
  import "../chunk-ITQ7352M.js";
2
+ import {
3
+ signInAction
4
+ } from "../chunk-7QF22LHP.js";
5
+ import {
6
+ csrfTokenAction
7
+ } from "../chunk-ICAZ4OVS.js";
2
8
  import {
3
9
  signOutAction
4
- } from "../chunk-A3N4PVAT.js";
10
+ } from "../chunk-ALG3GIV4.js";
5
11
  import {
6
12
  callbackAction
7
- } from "../chunk-KSWLO5ZU.js";
8
- import "../chunk-GA2SMTJO.js";
9
- import "../chunk-IVET23KF.js";
10
- import {
11
- csrfTokenAction
12
- } from "../chunk-HT4YLL7N.js";
13
+ } from "../chunk-6MXFPFR3.js";
14
+ import "../chunk-TZB6MUXN.js";
15
+ import "../chunk-XGLBNXL4.js";
13
16
  import {
14
17
  sessionAction
15
- } from "../chunk-JVFTCTTE.js";
16
- import {
17
- signInAction
18
- } from "../chunk-3EUWD5BB.js";
19
- import "../chunk-N4SX7TZT.js";
20
- import "../chunk-W6LG7BFW.js";
21
- import "../chunk-STHEPPUZ.js";
22
- import "../chunk-N2APGLXA.js";
23
- import "../chunk-CXLATHS5.js";
24
- import "../chunk-EIL2FPSS.js";
25
- import "../chunk-RRLIF4PQ.js";
18
+ } from "../chunk-PHFH2MGS.js";
19
+ import "../chunk-XUP6KKNG.js";
26
20
  import "../chunk-ZNCZVF6U.js";
27
- import "../chunk-YRCB5FLE.js";
21
+ import "../chunk-KJBAQZX2.js";
22
+ import "../chunk-NUDITUKX.js";
23
+ import "../chunk-4EKY7655.js";
24
+ import "../chunk-QQVSRXGX.js";
25
+ import "../chunk-5W4BRQYG.js";
26
+ import "../chunk-EBAMFRB7.js";
27
+ import "../chunk-FRJFWTOY.js";
28
+ import "../chunk-4MYWAOLG.js";
29
+ import "../chunk-RRLIF4PQ.js";
28
30
  export {
29
31
  callbackAction,
30
32
  csrfTokenAction,
@@ -25,6 +25,34 @@ __export(session_exports, {
25
25
  module.exports = __toCommonJS(session_exports);
26
26
  var import_router2 = require("@aura-stack/router");
27
27
 
28
+ // src/headers.ts
29
+ var cacheControl = {
30
+ "Cache-Control": "no-store",
31
+ Pragma: "no-cache",
32
+ Expires: "0",
33
+ Vary: "Cookie"
34
+ };
35
+ var contentSecurityPolicy = {
36
+ "Content-Security-Policy": [
37
+ "default-src 'none'",
38
+ "script-src 'self'",
39
+ "frame-src 'none'",
40
+ "object-src 'none'",
41
+ "frame-ancestors 'none'",
42
+ "base-uri 'none'"
43
+ ].join("; ")
44
+ };
45
+ var secureHeaders = {
46
+ "X-Content-Type-Options": "nosniff",
47
+ "X-Frame-Options": "DENY",
48
+ "Referrer-Policy": "strict-origin-when-cross-origin"
49
+ };
50
+ var secureApiHeaders = {
51
+ ...cacheControl,
52
+ ...contentSecurityPolicy,
53
+ ...secureHeaders
54
+ };
55
+
28
56
  // src/utils.ts
29
57
  var import_router = require("@aura-stack/router");
30
58
 
@@ -44,13 +72,11 @@ var AuthInternalError = class extends Error {
44
72
  var toISOString = (date) => {
45
73
  return new Date(date).toISOString();
46
74
  };
47
-
48
- // src/headers.ts
49
- var cacheControl = {
50
- "Cache-Control": "no-store",
51
- Pragma: "no-cache",
52
- Expires: "0",
53
- Vary: "Cookie"
75
+ var getErrorName = (error) => {
76
+ if (error instanceof Error) {
77
+ return error.name;
78
+ }
79
+ return typeof error === "string" ? error : "UnknownError";
54
80
  };
55
81
 
56
82
  // src/cookie.ts
@@ -70,7 +96,8 @@ var oauthCookieOptions = {
70
96
  var expiredCookieAttributes = {
71
97
  ...defaultCookieOptions,
72
98
  expires: /* @__PURE__ */ new Date(0),
73
- maxAge: 0
99
+ maxAge: 0,
100
+ secure: true
74
101
  };
75
102
  var getCookie = (request, cookieName) => {
76
103
  const cookies = request.headers.get("Cookie");
@@ -88,16 +115,18 @@ var getCookie = (request, cookieName) => {
88
115
  var sessionAction = (0, import_router2.createEndpoint)("GET", "/session", async (ctx) => {
89
116
  const {
90
117
  request,
91
- context: { jose, cookies }
118
+ context: { jose, cookies, logger }
92
119
  } = ctx;
93
120
  try {
94
121
  const session = getCookie(request, cookies.sessionToken.name);
95
122
  const decoded = await jose.decodeJWT(session);
123
+ logger?.log("AUTH_SESSION_VALID");
96
124
  const { exp, iat, jti, nbf, ...user } = decoded;
97
- const headers = new Headers(cacheControl);
125
+ const headers = new Headers(secureApiHeaders);
98
126
  return Response.json({ user, expires: toISOString(exp * 1e3) }, { headers });
99
127
  } catch (error) {
100
- const headers = new import_router2.HeadersBuilder(cacheControl).setCookie(cookies.sessionToken.name, "", expiredCookieAttributes).toHeaders();
128
+ logger?.log("AUTH_SESSION_INVALID", { structuredData: { error_type: getErrorName(error) } });
129
+ const headers = new import_router2.HeadersBuilder(secureApiHeaders).setCookie(cookies.sessionToken.name, "", expiredCookieAttributes).toHeaders();
101
130
  return Response.json({ authenticated: false, message: "Unauthorized" }, { status: 401, headers });
102
131
  }
103
132
  });
@@ -1,7 +1,5 @@
1
1
  import * as _aura_stack_router from '@aura-stack/router';
2
2
 
3
- declare const sessionAction: _aura_stack_router.RouteEndpoint<"GET", "/session", {
4
- schemas?: _aura_stack_router.EndpointSchemas | undefined;
5
- }>;
3
+ declare const sessionAction: _aura_stack_router.RouteEndpoint<"GET", "/session", {}>;
6
4
 
7
5
  export { sessionAction };
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  sessionAction
3
- } from "../../chunk-JVFTCTTE.js";
4
- import "../../chunk-W6LG7BFW.js";
5
- import "../../chunk-STHEPPUZ.js";
6
- import "../../chunk-CXLATHS5.js";
3
+ } from "../../chunk-PHFH2MGS.js";
4
+ import "../../chunk-QQVSRXGX.js";
5
+ import "../../chunk-5W4BRQYG.js";
6
+ import "../../chunk-EBAMFRB7.js";
7
7
  import "../../chunk-RRLIF4PQ.js";
8
8
  export {
9
9
  sessionAction
@@ -23,19 +23,37 @@ __export(authorization_exports, {
23
23
  createAuthorizationURL: () => createAuthorizationURL,
24
24
  createRedirectTo: () => createRedirectTo,
25
25
  createRedirectURI: () => createRedirectURI,
26
- getOriginURL: () => getOriginURL
26
+ getOriginURL: () => getOriginURL,
27
+ getTrustedOrigins: () => getTrustedOrigins
27
28
  });
28
29
  module.exports = __toCommonJS(authorization_exports);
29
30
 
30
- // src/assert.ts
31
- var isValidURL = (value) => {
32
- if (value.includes("\r\n") || value.includes("\n") || value.includes("\r")) return false;
33
- const regex = /^https?:\/\/(?:[a-zA-Z0-9._-]+|localhost|\[[0-9a-fA-F:]+\])(?::\d{1,5})?(?:\/[a-zA-Z0-9._~!$&'()*+,;=:@-]*)*\/?$/;
34
- return regex.test(value);
31
+ // src/errors.ts
32
+ var AuthInternalError = class extends Error {
33
+ type = "AUTH_INTERNAL_ERROR";
34
+ code;
35
+ constructor(code, message, options2) {
36
+ super(message, options2);
37
+ this.code = code;
38
+ this.name = new.target.name;
39
+ Error.captureStackTrace(this, new.target);
40
+ }
35
41
  };
36
42
 
37
43
  // src/schemas.ts
38
44
  var import_zod = require("zod");
45
+ var OAuthProviderCredentialsSchema = (0, import_zod.object)({
46
+ id: (0, import_zod.string)(),
47
+ name: (0, import_zod.string)(),
48
+ authorizeURL: (0, import_zod.string)().url(),
49
+ accessToken: (0, import_zod.string)().url(),
50
+ scope: (0, import_zod.string)(),
51
+ userInfo: (0, import_zod.string)().url(),
52
+ responseType: (0, import_zod.enum)(["code", "token", "id_token"]),
53
+ clientId: (0, import_zod.string)(),
54
+ clientSecret: (0, import_zod.string)(),
55
+ profile: import_zod.z.function().optional()
56
+ });
39
57
  var OAuthProviderConfigSchema = (0, import_zod.object)({
40
58
  authorizeURL: (0, import_zod.string)().url(),
41
59
  accessToken: (0, import_zod.string)().url(),
@@ -102,31 +120,6 @@ var OAuthEnvSchema = (0, import_zod.object)({
102
120
  clientSecret: import_zod.z.string().min(1, "OAuth Client Secret is required in the environment variables.")
103
121
  });
104
122
 
105
- // src/errors.ts
106
- var AuthInternalError = class extends Error {
107
- type = "AUTH_INTERNAL_ERROR";
108
- code;
109
- constructor(code, message, options2) {
110
- super(message, options2);
111
- this.code = code;
112
- this.name = new.target.name;
113
- Error.captureStackTrace(this, new.target);
114
- }
115
- };
116
- var AuthSecurityError = class extends Error {
117
- type = "AUTH_SECURITY_ERROR";
118
- code;
119
- constructor(code, message, options2) {
120
- super(message, options2);
121
- this.code = code;
122
- this.name = new.target.name;
123
- Error.captureStackTrace(this, new.target);
124
- }
125
- };
126
- var isAuthSecurityError = (error) => {
127
- return error instanceof AuthSecurityError;
128
- };
129
-
130
123
  // src/utils.ts
131
124
  var import_router = require("@aura-stack/router");
132
125
  var toSnakeCase = (str) => {
@@ -145,133 +138,178 @@ var equals = (a, b) => {
145
138
  if (a === null || b === null || a === void 0 || b === void 0) return false;
146
139
  return a === b;
147
140
  };
148
- var sanitizeURL = (url) => {
149
- try {
150
- let decodedURL = decodeURIComponent(url).trim();
151
- const protocolMatch = decodedURL.match(/^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)/);
152
- let protocol = "";
153
- let rest = decodedURL;
154
- if (protocolMatch) {
155
- protocol = protocolMatch[1];
156
- rest = decodedURL.slice(protocol.length);
157
- const slashIndex = rest.indexOf("/");
158
- if (slashIndex === -1) {
159
- return protocol + rest;
160
- }
161
- const domain = rest.slice(0, slashIndex);
162
- let path = rest.slice(slashIndex).replace(/\/\.\.\//g, "/").replace(/\/\.\.$/, "").replace(/\.{2,}/g, "").replace(/\/{2,}/g, "/");
163
- if (path !== "/" && path.endsWith("/")) {
164
- path = path.replace(/\/+$/, "/");
165
- } else if (path !== "/") {
166
- path = path.replace(/\/+$/, "");
167
- }
168
- return protocol + domain + path;
169
- }
170
- let sanitized = decodedURL.replace(/\/\.\.\//g, "/").replace(/\/\.\.$/, "").replace(/\.{2,}/g, "").replace(/\/{2,}/g, "/");
171
- if (sanitized !== "/" && sanitized.endsWith("/")) {
172
- sanitized = sanitized.replace(/\/+$/, "/");
173
- } else if (sanitized !== "/") {
174
- sanitized = sanitized.replace(/\/+$/, "");
175
- }
176
- return sanitized;
177
- } catch {
178
- return url.trim();
141
+ var extractPath = (url) => {
142
+ const pathRegex = /^https?:\/\/[a-zA-Z0-9_\-\.]+(:\d+)?(\/.*)$/;
143
+ const match = url.match(pathRegex);
144
+ return match && match[2] ? match[2] : "/";
145
+ };
146
+
147
+ // src/assert.ts
148
+ var unsafeChars = [
149
+ "<",
150
+ ">",
151
+ '"',
152
+ "`",
153
+ " ",
154
+ "\r",
155
+ "\n",
156
+ " ",
157
+ "\\",
158
+ "%2F",
159
+ "%5C",
160
+ "%2f",
161
+ "%5c",
162
+ "\r\n",
163
+ "%0A",
164
+ "%0D",
165
+ "%0a",
166
+ "%0d",
167
+ "..",
168
+ "//",
169
+ "///",
170
+ "...",
171
+ "%20",
172
+ "\0"
173
+ ];
174
+ var isValidURL = (value) => {
175
+ if (!new RegExp(/^https?:\/\/[^/]/).test(value)) {
176
+ return false;
179
177
  }
178
+ const match = value.match(/^(https?:\/\/)(.*)$/);
179
+ if (!match) return false;
180
+ const rest = match[2];
181
+ for (const char of unsafeChars) {
182
+ if (rest.includes(char)) return false;
183
+ }
184
+ const regex = /^https?:\/\/(?:[a-zA-Z0-9._-]+|localhost|\[[0-9a-fA-F:]+\])(?::\d{1,5})?(?:\/[a-zA-Z0-9._~!$&'()?#*+,;=:@-]*)*\/?$/;
185
+ return regex.test(match[0]);
180
186
  };
181
- var getNormalizedOriginPath = (path) => {
187
+ var isRelativeURL = (value) => {
188
+ if (value.length > 100) return false;
189
+ for (const char of unsafeChars) {
190
+ if (value.includes(char)) return false;
191
+ }
192
+ const regex = /^\/[a-zA-Z0-9\-_\/.?&=#]*\/?$/;
193
+ return regex.test(value);
194
+ };
195
+ var isSameOrigin = (origin, expected) => {
196
+ const originURL = new URL(origin);
197
+ const expectedURL = new URL(expected);
198
+ return equals(originURL.origin, expectedURL.origin);
199
+ };
200
+ var patternToRegex = (pattern) => {
182
201
  try {
183
- const url = new URL(path);
184
- url.hash = "";
185
- url.search = "";
186
- return `${url.origin}${url.pathname}`;
202
+ if (pattern.length > 2048) return null;
203
+ pattern = pattern.replace(/\\/g, "");
204
+ const match = pattern.match(/^(https?):\/\/([a-zA-Z0-9.*-]{1,253})(?::(\d{1,5}|\*))?(?:\/.*)?$/);
205
+ if (!match) return null;
206
+ const [, protocol, host, port] = match;
207
+ const hasWildcard = host.includes("*");
208
+ if (hasWildcard && !host.startsWith("*.")) return null;
209
+ if (hasWildcard && host.slice(2).includes("*")) return null;
210
+ const domain = hasWildcard ? host.slice(2) : host;
211
+ const escapedDomain = domain.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
212
+ const hostRegex = hasWildcard ? `[^.]+\\.${escapedDomain}` : escapedDomain;
213
+ const portRegex = port === "*" ? ":\\d{1,5}" : port ? `:${port}` : "";
214
+ return new RegExp(`^${protocol}:\\/\\/${hostRegex}${portRegex}$`);
187
215
  } catch {
188
- return sanitizeURL(path);
216
+ return null;
189
217
  }
190
218
  };
191
- var formatZodError = (error) => {
192
- if (!error.issues || error.issues.length === 0) {
193
- return {};
194
- }
195
- return error.issues.reduce((previous, issue) => {
196
- const key = issue.path.join(".");
197
- return {
198
- ...previous,
199
- [key]: {
200
- code: issue.code,
201
- message: issue.message
219
+ var isTrustedOrigin = (url, trustedOrigins) => {
220
+ if (!isValidURL(url) || trustedOrigins.length === 0) return false;
221
+ try {
222
+ const urlOrigin = new URL(url).origin;
223
+ for (const pattern of trustedOrigins) {
224
+ const regex = patternToRegex(pattern);
225
+ if (regex?.test(urlOrigin)) return true;
226
+ try {
227
+ if (isValidURL(pattern) && equals(new URL(pattern).origin, urlOrigin)) return true;
228
+ } catch {
202
229
  }
203
- };
204
- }, {});
230
+ }
231
+ } catch {
232
+ }
233
+ return false;
205
234
  };
206
235
 
207
236
  // src/actions/signIn/authorization.ts
208
- var createAuthorizationURL = (oauthConfig, redirectURI, state, codeChallenge, codeChallengeMethod) => {
237
+ var createAuthorizationURL = (oauthConfig, redirectURI, state, codeChallenge, codeChallengeMethod, logger) => {
209
238
  const parsed = OAuthAuthorization.safeParse({ ...oauthConfig, redirectURI, state, codeChallenge, codeChallengeMethod });
210
239
  if (!parsed.success) {
211
- const msg = JSON.stringify(formatZodError(parsed.error), null, 2);
212
- throw new AuthInternalError("INVALID_OAUTH_CONFIGURATION", msg);
240
+ logger?.log("INVALID_OAUTH_CONFIGURATION", {
241
+ structuredData: {
242
+ scope: oauthConfig.scope,
243
+ redirect_uri: redirectURI,
244
+ has_state: Boolean(state),
245
+ has_code_challenge: Boolean(codeChallenge),
246
+ code_challenge_method: codeChallengeMethod
247
+ }
248
+ });
249
+ throw new AuthInternalError("INVALID_OAUTH_CONFIGURATION", "The OAuth provider configuration is invalid.");
213
250
  }
214
251
  const { authorizeURL, ...options2 } = parsed.data;
215
252
  const { userInfo, accessToken, clientSecret, ...required } = options2;
216
253
  const searchParams = new URLSearchParams(toCastCase(required));
217
254
  return `${authorizeURL}?${searchParams}`;
218
255
  };
219
- var getOriginURL = (request, trustedProxyHeaders) => {
256
+ var getTrustedOrigins = async (request, trustedOrigins) => {
257
+ if (!trustedOrigins) return [];
258
+ const raw = typeof trustedOrigins === "function" ? await trustedOrigins(request) : trustedOrigins;
259
+ return Array.isArray(raw) ? raw : typeof raw === "string" ? [raw] : [];
260
+ };
261
+ var getOriginURL = async (request, context) => {
220
262
  const headers = request.headers;
221
- if (trustedProxyHeaders) {
222
- const protocol = headers.get("X-Forwarded-Proto") ?? headers.get("Forwarded")?.match(/proto=([^;]+)/i)?.[1] ?? "http";
223
- const host = headers.get("X-Forwarded-Host") ?? headers.get("Host") ?? headers.get("Forwarded")?.match(/host=([^;]+)/i)?.[1] ?? null;
224
- return new URL(`${protocol}://${host}${getNormalizedOriginPath(new URL(request.url).pathname)}`);
225
- } else {
226
- return new URL(getNormalizedOriginPath(request.url));
263
+ let origin = new URL(request.url).origin;
264
+ const trustedOrigins = await getTrustedOrigins(request, context?.trustedOrigins);
265
+ trustedOrigins.push(origin);
266
+ if (context?.trustedProxyHeaders) {
267
+ const protocol = headers.get("Forwarded")?.match(/proto=([^;]+)/i)?.[1] ?? headers.get("X-Forwarded-Proto") ?? "http";
268
+ const host = headers.get("Host") ?? headers.get("Forwarded")?.match(/host=([^;]+)/i)?.[1] ?? headers.get("X-Forwarded-Host") ?? null;
269
+ origin = `${protocol}://${host}`;
270
+ }
271
+ if (!isTrustedOrigin(origin, trustedOrigins)) {
272
+ context?.logger?.log("UNTRUSTED_ORIGIN", { structuredData: { origin } });
273
+ throw new AuthInternalError("UNTRUSTED_ORIGIN", "The constructed origin URL is not trusted.");
227
274
  }
275
+ return origin;
228
276
  };
229
- var createRedirectURI = (request, oauth, basePath, trustedProxyHeaders) => {
230
- const url = getOriginURL(request, trustedProxyHeaders);
231
- return `${url.origin}${basePath}/callback/${oauth}`;
277
+ var createRedirectURI = async (request, oauth, context) => {
278
+ const origin = await getOriginURL(request, context);
279
+ return `${origin}${context.basePath}/callback/${oauth}`;
232
280
  };
233
- var createRedirectTo = (request, redirectTo, trustedProxyHeaders) => {
281
+ var createRedirectTo = async (request, redirectTo, context) => {
234
282
  try {
235
283
  const headers = request.headers;
236
- const origin = headers.get("Origin");
237
- const referer = headers.get("Referer");
238
- let hostedURL = getOriginURL(request, trustedProxyHeaders);
239
- if (redirectTo) {
240
- if (redirectTo.startsWith("/")) {
241
- return sanitizeURL(redirectTo);
284
+ const requestOrigin = await getOriginURL(request, context);
285
+ const origins = await getTrustedOrigins(request, context?.trustedOrigins);
286
+ const validateURL = (url) => {
287
+ if (!isRelativeURL(url) && !isValidURL(url)) return "/";
288
+ if (isRelativeURL(url)) return url;
289
+ if (origins.length > 0) {
290
+ if (isTrustedOrigin(url, origins)) {
291
+ const urlOrigin = new URL(url).origin;
292
+ for (const pattern of origins) {
293
+ const regex = patternToRegex(pattern);
294
+ if (regex?.test(urlOrigin)) {
295
+ return isSameOrigin(url, request.url) ? extractPath(url) : url;
296
+ }
297
+ if (isValidURL(pattern) && equals(new URL(pattern).origin, urlOrigin)) return url;
298
+ }
299
+ }
300
+ context?.logger?.log("OPEN_REDIRECT_ATTACK");
301
+ return "/";
242
302
  }
243
- const redirectToURL = new URL(sanitizeURL(getNormalizedOriginPath(redirectTo)));
244
- if (!isValidURL(redirectTo) || !equals(redirectToURL.origin, hostedURL.origin)) {
245
- throw new AuthSecurityError(
246
- "POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
247
- "The redirectTo parameter does not match the hosted origin."
248
- );
303
+ if (isSameOrigin(url, requestOrigin)) {
304
+ return extractPath(url);
249
305
  }
250
- return sanitizeURL(redirectToURL.pathname);
251
- }
252
- if (referer) {
253
- const refererURL = new URL(sanitizeURL(referer));
254
- if (!isValidURL(referer) || !equals(refererURL.origin, hostedURL.origin)) {
255
- throw new AuthSecurityError(
256
- "POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
257
- "The referer of the request does not match the hosted origin."
258
- );
259
- }
260
- return sanitizeURL(refererURL.pathname);
261
- }
262
- if (origin) {
263
- const originURL = new URL(sanitizeURL(getNormalizedOriginPath(origin)));
264
- if (!isValidURL(origin) || !equals(originURL.origin, hostedURL.origin)) {
265
- throw new AuthSecurityError("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", "Invalid origin (potential CSRF).");
266
- }
267
- return sanitizeURL(originURL.pathname);
268
- }
269
- return "/";
306
+ context?.logger?.log("OPEN_REDIRECT_ATTACK");
307
+ return "/";
308
+ };
309
+ return validateURL(redirectTo ?? headers.get("Referer") ?? headers.get("Origin") ?? "/");
270
310
  } catch (error) {
271
- if (isAuthSecurityError(error)) {
272
- throw error;
273
- }
274
- throw new AuthSecurityError("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", "Invalid origin (potential CSRF).");
311
+ context?.logger?.log("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED");
312
+ return "/";
275
313
  }
276
314
  };
277
315
  // Annotate the CommonJS export names for ESM import in node:
@@ -279,5 +317,6 @@ var createRedirectTo = (request, redirectTo, trustedProxyHeaders) => {
279
317
  createAuthorizationURL,
280
318
  createRedirectTo,
281
319
  createRedirectURI,
282
- getOriginURL
320
+ getOriginURL,
321
+ getTrustedOrigins
283
322
  });
@@ -1,9 +1,11 @@
1
- import { h as OAuthProviderCredentials } from '../../index-DkaLJFn8.js';
1
+ import { GlobalContext } from '@aura-stack/router';
2
+ import { h as OAuthProviderCredentials, I as InternalLogger, d as AuthConfig } from '../../index-CSyIJmCM.js';
2
3
  import 'zod';
3
4
  import '../../schemas.js';
4
- import '@aura-stack/router/cookie';
5
+ import '../../jose.js';
5
6
  import '@aura-stack/jose';
6
7
  import '@aura-stack/jose/jose';
8
+ import '@aura-stack/router/cookie';
7
9
  import '../../@types/utility.js';
8
10
 
9
11
  /**
@@ -18,26 +20,34 @@ import '../../@types/utility.js';
18
20
  * @param redirectURI - The redirect URI where the OAuth service will send the user after authorization.
19
21
  * @param state - A unique string used to maintain state between the request and callback.
20
22
  */
21
- declare const createAuthorizationURL: (oauthConfig: OAuthProviderCredentials, redirectURI: string, state: string, codeChallenge: string, codeChallengeMethod: string) => string;
22
- declare const getOriginURL: (request: Request, trustedProxyHeaders?: boolean) => URL;
23
+ declare const createAuthorizationURL: (oauthConfig: OAuthProviderCredentials, redirectURI: string, state: string, codeChallenge: string, codeChallengeMethod: string, logger?: InternalLogger) => string;
24
+ /**
25
+ * Resolves trusted origins from config (array or function).
26
+ */
27
+ declare const getTrustedOrigins: (request: Request, trustedOrigins: AuthConfig["trustedOrigins"]) => Promise<string[]>;
28
+ declare const getOriginURL: (request: Request, context?: GlobalContext) => Promise<string>;
23
29
  /**
24
30
  * Creates the redirect URI for the OAuth callback based on the original request URL and the OAuth provider.
25
31
  *
26
32
  * @param requestURL - the original request URL
27
33
  * @param oauth - OAuth provider name
34
+ * @param context - Global context containing configuration and utilities
28
35
  * @returns The redirect URI for the OAuth callback.
29
36
  */
30
- declare const createRedirectURI: (request: Request, oauth: string, basePath: string, trustedProxyHeaders?: boolean) => string;
37
+ declare const createRedirectURI: (request: Request, oauth: string, context: GlobalContext) => Promise<string>;
31
38
  /**
32
39
  * Verifies if the request's origin matches the expected origin. It accepts the redirectTo search
33
- * parameter for redirection. It checks the 'Referer' header of the request with the origin where
34
- * the authentication flow is hosted. If they do not match, it throws an AuthError to avoid
35
- * potential `Open URL Redirection` attacks.
40
+ * parameter for redirection. It checks the Referer and Origin headers and the request URL against
41
+ * the trusted origins list. If they do not match, it returns "/" to avoid potential open redirect attacks.
42
+ *
43
+ * When `trustedOrigins` is provided, URLs are validated against that list. When not provided,
44
+ * the request's derived origin (from request.url or proxy headers) is used as the only trusted origin.
36
45
  *
37
46
  * @param request The incoming request object
38
47
  * @param redirectTo Optional redirectTo parameter to override the referer
39
- * @returns The pathname of the referer URL if origins match
48
+ * @param context Global context containing configuration and utilities
49
+ * @returns A safe URL to redirect to after authentication, or "/" if the URL is not considered safe.
40
50
  */
41
- declare const createRedirectTo: (request: Request, redirectTo?: string, trustedProxyHeaders?: boolean) => string;
51
+ declare const createRedirectTo: (request: Request, redirectTo?: string, context?: GlobalContext) => Promise<string>;
42
52
 
43
- export { createAuthorizationURL, createRedirectTo, createRedirectURI, getOriginURL };
53
+ export { createAuthorizationURL, createRedirectTo, createRedirectURI, getOriginURL, getTrustedOrigins };
@@ -2,15 +2,17 @@ import {
2
2
  createAuthorizationURL,
3
3
  createRedirectTo,
4
4
  createRedirectURI,
5
- getOriginURL
6
- } from "../../chunk-N4SX7TZT.js";
7
- import "../../chunk-CXLATHS5.js";
8
- import "../../chunk-EIL2FPSS.js";
5
+ getOriginURL,
6
+ getTrustedOrigins
7
+ } from "../../chunk-XUP6KKNG.js";
8
+ import "../../chunk-KJBAQZX2.js";
9
+ import "../../chunk-4EKY7655.js";
10
+ import "../../chunk-QQVSRXGX.js";
9
11
  import "../../chunk-RRLIF4PQ.js";
10
- import "../../chunk-YRCB5FLE.js";
11
12
  export {
12
13
  createAuthorizationURL,
13
14
  createRedirectTo,
14
15
  createRedirectURI,
15
- getOriginURL
16
+ getOriginURL,
17
+ getTrustedOrigins
16
18
  };