@aura-stack/auth 0.4.0-rc.5 → 0.5.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 (201) hide show
  1. package/dist/@types/index.d.ts +8 -3
  2. package/dist/@types/router.d.cjs +0 -17
  3. package/dist/@types/router.d.d.ts +7 -2
  4. package/dist/@types/router.d.js +0 -1
  5. package/dist/actions/callback/access-token.cjs +130 -71
  6. package/dist/actions/callback/access-token.d.ts +9 -4
  7. package/dist/actions/callback/access-token.js +3 -4
  8. package/dist/actions/callback/callback.cjs +428 -152
  9. package/dist/actions/callback/callback.d.ts +11 -3
  10. package/dist/actions/callback/callback.js +12 -10
  11. package/dist/actions/callback/userinfo.cjs +159 -65
  12. package/dist/actions/callback/userinfo.d.ts +8 -3
  13. package/dist/actions/callback/userinfo.js +7 -6
  14. package/dist/actions/csrfToken/csrfToken.cjs +70 -19
  15. package/dist/actions/csrfToken/csrfToken.js +8 -7
  16. package/dist/actions/index.cjs +780 -348
  17. package/dist/actions/index.d.ts +6 -2
  18. package/dist/actions/index.js +23 -18
  19. package/dist/actions/session/session.cjs +107 -26
  20. package/dist/actions/session/session.js +7 -5
  21. package/dist/actions/signIn/authorization-url.cjs +288 -0
  22. package/dist/actions/signIn/authorization-url.d.ts +31 -0
  23. package/dist/actions/signIn/authorization-url.js +16 -0
  24. package/dist/actions/signIn/authorization.cjs +209 -211
  25. package/dist/actions/signIn/authorization.d.ts +32 -21
  26. package/dist/actions/signIn/authorization.js +12 -9
  27. package/dist/actions/signIn/signIn.cjs +470 -235
  28. package/dist/actions/signIn/signIn.d.ts +12 -3
  29. package/dist/actions/signIn/signIn.js +11 -8
  30. package/dist/actions/signOut/signOut.cjs +376 -228
  31. package/dist/actions/signOut/signOut.d.ts +1 -1
  32. package/dist/actions/signOut/signOut.js +10 -9
  33. package/dist/api/createApi.cjs +750 -0
  34. package/dist/api/createApi.d.ts +12 -0
  35. package/dist/api/createApi.js +19 -0
  36. package/dist/api/getSession.cjs +141 -0
  37. package/dist/api/getSession.d.ts +16 -0
  38. package/dist/api/getSession.js +10 -0
  39. package/dist/api/signIn.cjs +549 -0
  40. package/dist/api/signIn.d.ts +26 -0
  41. package/dist/api/signIn.js +15 -0
  42. package/dist/api/signOut.cjs +279 -0
  43. package/dist/api/signOut.d.ts +16 -0
  44. package/dist/api/signOut.js +13 -0
  45. package/dist/assert.cjs +150 -5
  46. package/dist/assert.d.ts +26 -3
  47. package/dist/assert.js +17 -3
  48. package/dist/{chunk-YRCB5FLE.js → chunk-2A5B7GWR.js} +52 -6
  49. package/dist/chunk-2GQLSIJ2.js +40 -0
  50. package/dist/chunk-2IR674WX.js +44 -0
  51. package/dist/chunk-3J5TUH2I.js +50 -0
  52. package/dist/chunk-4RWSYUKX.js +98 -0
  53. package/dist/chunk-4YHJ4IEQ.js +25 -0
  54. package/dist/chunk-54CZPKR4.js +25 -0
  55. package/dist/chunk-5LZ7TOM3.js +25 -0
  56. package/dist/chunk-7BE46WWS.js +88 -0
  57. package/dist/chunk-7YYXFKLR.js +35 -0
  58. package/dist/chunk-C3A37LQC.js +33 -0
  59. package/dist/chunk-CITNGXDA.js +31 -0
  60. package/dist/chunk-CWX724AG.js +78 -0
  61. package/dist/chunk-D2CSIUKP.js +74 -0
  62. package/dist/chunk-E6G5YCI6.js +25 -0
  63. package/dist/chunk-EBAMFRB7.js +34 -0
  64. package/dist/chunk-EEE7UM5T.js +25 -0
  65. package/dist/{chunk-HT4YLL7N.js → chunk-FPCVZUVG.js} +10 -8
  66. package/dist/chunk-FW4W3REU.js +25 -0
  67. package/dist/chunk-GNNBM2WJ.js +83 -0
  68. package/dist/chunk-IPKO6UQN.js +25 -0
  69. package/dist/chunk-JOCGX3RP.js +59 -0
  70. package/dist/chunk-KBXWTD6E.js +94 -0
  71. package/dist/chunk-KMMAZFSJ.js +25 -0
  72. package/dist/chunk-LATR3NIV.js +117 -0
  73. package/dist/chunk-LAYPUDQF.js +39 -0
  74. package/dist/chunk-LDU7A2JE.js +25 -0
  75. package/dist/chunk-LX3TJ2TJ.js +294 -0
  76. package/dist/chunk-NHZBQNRR.js +143 -0
  77. package/dist/chunk-OVHNRULD.js +33 -0
  78. package/dist/chunk-PDP3PHB3.js +127 -0
  79. package/dist/chunk-PHYNROD4.js +47 -0
  80. package/dist/chunk-QQEKY4XP.js +29 -0
  81. package/dist/chunk-U4RK4LKJ.js +348 -0
  82. package/dist/{chunk-RRLIF4PQ.js → chunk-U5663F2U.js} +16 -1
  83. package/dist/chunk-UN7X6SU5.js +53 -0
  84. package/dist/chunk-UZQJJD6A.js +100 -0
  85. package/dist/chunk-V6LLEAR4.js +80 -0
  86. package/dist/chunk-WHNDRO3N.js +50 -0
  87. package/dist/{chunk-W6LG7BFW.js → chunk-XY5R3EHH.js} +30 -23
  88. package/dist/client/client.cjs +135 -0
  89. package/dist/client/client.d.ts +85 -0
  90. package/dist/client/client.js +9 -0
  91. package/dist/client/index.cjs +135 -0
  92. package/dist/client/index.d.ts +14 -0
  93. package/dist/client/index.js +10 -0
  94. package/dist/context.cjs +1237 -0
  95. package/dist/context.d.ts +16 -0
  96. package/dist/context.js +28 -0
  97. package/dist/cookie.cjs +57 -22
  98. package/dist/cookie.d.ts +11 -6
  99. package/dist/cookie.js +3 -2
  100. package/dist/createAuth.cjs +2320 -0
  101. package/dist/createAuth.d.ts +12 -0
  102. package/dist/createAuth.js +48 -0
  103. package/dist/env.cjs +78 -0
  104. package/dist/env.d.ts +10 -0
  105. package/dist/env.js +12 -0
  106. package/dist/errors.cjs +17 -0
  107. package/dist/errors.d.ts +15 -4
  108. package/dist/errors.js +5 -1
  109. package/dist/headers.cjs +28 -2
  110. package/dist/headers.d.ts +25 -1
  111. package/dist/headers.js +9 -3
  112. package/dist/index-_aXtxb_s.d.ts +1377 -0
  113. package/dist/index.cjs +1843 -610
  114. package/dist/index.d.ts +11 -92
  115. package/dist/index.js +53 -85
  116. package/dist/jose.cjs +113 -38
  117. package/dist/jose.d.ts +12 -23
  118. package/dist/jose.js +17 -7
  119. package/dist/logger.cjs +424 -0
  120. package/dist/logger.d.ts +12 -0
  121. package/dist/logger.js +17 -0
  122. package/dist/oauth/atlassian.cjs +57 -0
  123. package/dist/oauth/atlassian.d.ts +12 -0
  124. package/dist/oauth/atlassian.js +6 -0
  125. package/dist/oauth/bitbucket.cjs +19 -15
  126. package/dist/oauth/bitbucket.d.ts +7 -2
  127. package/dist/oauth/bitbucket.js +1 -1
  128. package/dist/oauth/discord.cjs +27 -24
  129. package/dist/oauth/discord.d.ts +7 -2
  130. package/dist/oauth/discord.js +1 -1
  131. package/dist/oauth/dropbox.cjs +53 -0
  132. package/dist/oauth/dropbox.d.ts +12 -0
  133. package/dist/oauth/dropbox.js +6 -0
  134. package/dist/oauth/figma.cjs +19 -16
  135. package/dist/oauth/figma.d.ts +7 -2
  136. package/dist/oauth/figma.js +1 -1
  137. package/dist/oauth/github.cjs +19 -8
  138. package/dist/oauth/github.d.ts +7 -2
  139. package/dist/oauth/github.js +1 -1
  140. package/dist/oauth/gitlab.cjs +19 -16
  141. package/dist/oauth/gitlab.d.ts +7 -2
  142. package/dist/oauth/gitlab.js +1 -1
  143. package/dist/oauth/index.cjs +529 -239
  144. package/dist/oauth/index.d.ts +7 -2
  145. package/dist/oauth/index.js +39 -22
  146. package/dist/oauth/mailchimp.cjs +19 -16
  147. package/dist/oauth/mailchimp.d.ts +7 -2
  148. package/dist/oauth/mailchimp.js +1 -1
  149. package/dist/oauth/notion.cjs +131 -0
  150. package/dist/oauth/notion.d.ts +12 -0
  151. package/dist/oauth/notion.js +9 -0
  152. package/dist/oauth/pinterest.cjs +19 -16
  153. package/dist/oauth/pinterest.d.ts +7 -2
  154. package/dist/oauth/pinterest.js +1 -1
  155. package/dist/oauth/spotify.cjs +19 -16
  156. package/dist/oauth/spotify.d.ts +7 -2
  157. package/dist/oauth/spotify.js +1 -1
  158. package/dist/oauth/strava.cjs +19 -16
  159. package/dist/oauth/strava.d.ts +7 -2
  160. package/dist/oauth/strava.js +1 -1
  161. package/dist/oauth/twitch.cjs +95 -0
  162. package/dist/oauth/twitch.d.ts +12 -0
  163. package/dist/oauth/twitch.js +7 -0
  164. package/dist/oauth/x.cjs +19 -16
  165. package/dist/oauth/x.d.ts +7 -2
  166. package/dist/oauth/x.js +1 -1
  167. package/dist/schemas.cjs +89 -42
  168. package/dist/schemas.d.ts +114 -18
  169. package/dist/schemas.js +5 -3
  170. package/dist/secure.cjs +73 -31
  171. package/dist/secure.d.ts +11 -11
  172. package/dist/secure.js +7 -6
  173. package/dist/utils.cjs +203 -90
  174. package/dist/utils.d.ts +21 -40
  175. package/dist/utils.js +21 -12
  176. package/package.json +9 -6
  177. package/dist/chunk-3EUWD5BB.js +0 -63
  178. package/dist/chunk-42XB3YCW.js +0 -22
  179. package/dist/chunk-6R2YZ4AC.js +0 -22
  180. package/dist/chunk-A3N4PVAT.js +0 -70
  181. package/dist/chunk-B737EUJV.js +0 -22
  182. package/dist/chunk-CXLATHS5.js +0 -143
  183. package/dist/chunk-E3OXBRYF.js +0 -22
  184. package/dist/chunk-EIL2FPSS.js +0 -22
  185. package/dist/chunk-EMKJA2GJ.js +0 -89
  186. package/dist/chunk-FIPU4MLT.js +0 -21
  187. package/dist/chunk-FKRDCWBF.js +0 -22
  188. package/dist/chunk-GA2SMTJO.js +0 -58
  189. package/dist/chunk-HP34YGGJ.js +0 -22
  190. package/dist/chunk-IKHPGFCW.js +0 -14
  191. package/dist/chunk-IUYZQTJV.js +0 -30
  192. package/dist/chunk-IVET23KF.js +0 -58
  193. package/dist/chunk-JVFTCTTE.js +0 -33
  194. package/dist/chunk-KRNOMBXQ.js +0 -22
  195. package/dist/chunk-KSWLO5ZU.js +0 -102
  196. package/dist/chunk-N2APGLXA.js +0 -71
  197. package/dist/chunk-N4SX7TZT.js +0 -96
  198. package/dist/chunk-STHEPPUZ.js +0 -11
  199. package/dist/chunk-TLE4PXY3.js +0 -39
  200. package/dist/index-B8jeIElf.d.ts +0 -679
  201. /package/dist/{chunk-DIVDFNAP.js → chunk-5X7JZMEF.js} +0 -0
@@ -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/index.ts
@@ -39,8 +29,7 @@ __export(actions_exports, {
39
29
  module.exports = __toCommonJS(actions_exports);
40
30
 
41
31
  // src/actions/signIn/signIn.ts
42
- var import_zod2 = require("zod");
43
- var import_router2 = require("@aura-stack/router");
32
+ var import_v42 = require("zod/v4");
44
33
 
45
34
  // src/headers.ts
46
35
  var cacheControl = {
@@ -49,12 +38,26 @@ var cacheControl = {
49
38
  Expires: "0",
50
39
  Vary: "Cookie"
51
40
  };
52
-
53
- // src/secure.ts
54
- var import_crypto = __toESM(require("crypto"), 1);
55
-
56
- // src/utils.ts
57
- var import_router = require("@aura-stack/router");
41
+ var contentSecurityPolicy = {
42
+ "Content-Security-Policy": [
43
+ "default-src 'none'",
44
+ "script-src 'self'",
45
+ "frame-src 'none'",
46
+ "object-src 'none'",
47
+ "frame-ancestors 'none'",
48
+ "base-uri 'none'"
49
+ ].join("; ")
50
+ };
51
+ var secureHeaders = {
52
+ "X-Content-Type-Options": "nosniff",
53
+ "X-Frame-Options": "DENY",
54
+ "Referrer-Policy": "strict-origin-when-cross-origin"
55
+ };
56
+ var secureApiHeaders = {
57
+ ...cacheControl,
58
+ ...contentSecurityPolicy,
59
+ ...secureHeaders
60
+ };
58
61
 
59
62
  // src/errors.ts
60
63
  var OAuthProtocolError = class extends Error {
@@ -95,124 +98,322 @@ var isNativeError = (error) => {
95
98
  var isOAuthProtocolError = (error) => {
96
99
  return error instanceof OAuthProtocolError;
97
100
  };
98
- var isAuthSecurityError = (error) => {
99
- return error instanceof AuthSecurityError;
100
- };
101
+
102
+ // src/api/signIn.ts
103
+ var import_router2 = require("@aura-stack/router");
104
+
105
+ // src/schemas.ts
106
+ var import_v4 = require("zod/v4");
107
+ var AuthorizeConfigSchema = import_v4.z.union([
108
+ (0, import_v4.string)().url(),
109
+ (0, import_v4.object)({
110
+ url: (0, import_v4.string)().url(),
111
+ params: (0, import_v4.object)({
112
+ responseType: (0, import_v4.enum)(["code", "token", "id_token", "refresh_token"]).optional(),
113
+ scope: (0, import_v4.string)().optional()
114
+ })
115
+ })
116
+ ]);
117
+ var AccessTokenConfigSchema = import_v4.z.union([
118
+ (0, import_v4.string)().url(),
119
+ (0, import_v4.object)({
120
+ url: (0, import_v4.string)().url(),
121
+ headers: import_v4.z.record((0, import_v4.string)(), (0, import_v4.string)()).optional()
122
+ })
123
+ ]);
124
+ var UserInfoConfigSchema = import_v4.z.union([
125
+ (0, import_v4.string)().url(),
126
+ (0, import_v4.object)({
127
+ url: (0, import_v4.string)().url(),
128
+ headers: import_v4.z.record((0, import_v4.string)(), (0, import_v4.string)()).optional(),
129
+ method: (0, import_v4.string)().optional()
130
+ })
131
+ ]);
132
+ var OAuthProviderCredentialsSchema = (0, import_v4.object)({
133
+ id: (0, import_v4.string)(),
134
+ name: (0, import_v4.string)(),
135
+ authorize: AuthorizeConfigSchema.optional(),
136
+ /** @deprecated */
137
+ authorizeURL: (0, import_v4.string)().url().optional(),
138
+ accessToken: AccessTokenConfigSchema,
139
+ /** @deprecated */
140
+ scope: (0, import_v4.string)().optional(),
141
+ userInfo: UserInfoConfigSchema,
142
+ /** @deprecated */
143
+ responseType: (0, import_v4.enum)(["code", "token", "id_token", "refresh_token"]).optional(),
144
+ clientId: (0, import_v4.string)(),
145
+ clientSecret: (0, import_v4.string)(),
146
+ profile: import_v4.z.function().optional()
147
+ });
148
+ var OAuthProviderConfigSchema = (0, import_v4.object)({
149
+ authorize: AuthorizeConfigSchema.optional(),
150
+ /** @deprecated */
151
+ authorizeURL: (0, import_v4.string)().url().optional(),
152
+ accessToken: AccessTokenConfigSchema,
153
+ /** @deprecated */
154
+ scope: (0, import_v4.string)().optional(),
155
+ userInfo: UserInfoConfigSchema,
156
+ /** @deprecated */
157
+ responseType: (0, import_v4.enum)(["code", "token", "id_token", "refresh_token"]).optional(),
158
+ clientId: (0, import_v4.string)(),
159
+ clientSecret: (0, import_v4.string)()
160
+ });
161
+ var OAuthAuthorization = OAuthProviderConfigSchema.extend({
162
+ redirectURI: (0, import_v4.string)(),
163
+ state: (0, import_v4.string)(),
164
+ codeChallenge: (0, import_v4.string)(),
165
+ codeChallengeMethod: (0, import_v4.enum)(["plain", "S256"])
166
+ });
167
+ var OAuthAuthorizationResponse = (0, import_v4.object)({
168
+ state: (0, import_v4.string)({ message: "Missing state parameter in the OAuth authorization response." }),
169
+ code: (0, import_v4.string)({ message: "Missing code parameter in the OAuth authorization response." })
170
+ });
171
+ var OAuthAuthorizationErrorResponse = (0, import_v4.object)({
172
+ error: (0, import_v4.enum)([
173
+ "invalid_request",
174
+ "unauthorized_client",
175
+ "access_denied",
176
+ "unsupported_response_type",
177
+ "invalid_scope",
178
+ "server_error",
179
+ "temporarily_unavailable"
180
+ ]),
181
+ error_description: (0, import_v4.string)().optional(),
182
+ error_uri: (0, import_v4.string)().optional(),
183
+ state: (0, import_v4.string)()
184
+ });
185
+ var OAuthAccessToken = OAuthProviderConfigSchema.extend({
186
+ redirectURI: (0, import_v4.string)(),
187
+ code: (0, import_v4.string)(),
188
+ codeVerifier: (0, import_v4.string)().min(43).max(128)
189
+ });
190
+ var OAuthAccessTokenResponse = (0, import_v4.object)({
191
+ access_token: (0, import_v4.string)(),
192
+ token_type: (0, import_v4.string)().optional(),
193
+ expires_in: (0, import_v4.number)().optional(),
194
+ refresh_token: (0, import_v4.string)().optional(),
195
+ scope: (0, import_v4.union)([(0, import_v4.string)().optional().or((0, import_v4.null)()), (0, import_v4.array)((0, import_v4.string)()).optional()])
196
+ });
197
+ var OAuthAccessTokenErrorResponse = (0, import_v4.object)({
198
+ error: (0, import_v4.enum)([
199
+ "invalid_request",
200
+ "invalid_client",
201
+ "invalid_grant",
202
+ "unauthorized_client",
203
+ "unsupported_grant_type",
204
+ "invalid_scope"
205
+ ]),
206
+ error_description: (0, import_v4.string)().optional(),
207
+ error_uri: (0, import_v4.string)().optional()
208
+ });
209
+ var OAuthErrorResponse = (0, import_v4.object)({
210
+ error: (0, import_v4.string)(),
211
+ error_description: (0, import_v4.string)().optional()
212
+ });
213
+ var OAuthEnvSchema = (0, import_v4.object)({
214
+ clientId: import_v4.z.string().min(1, "OAuth Client ID is required in the environment variables."),
215
+ clientSecret: import_v4.z.string().min(1, "OAuth Client Secret is required in the environment variables.")
216
+ });
101
217
 
102
218
  // src/utils.ts
103
- var toSnakeCase = (str) => {
104
- return str.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").toLowerCase().replace(/^_+/, "");
219
+ var import_router = require("@aura-stack/router");
220
+
221
+ // src/env.ts
222
+ var import_meta = {};
223
+ var env = new Proxy({}, {
224
+ get(_, prop) {
225
+ if (typeof prop !== "string") return void 0;
226
+ const hasProperty = (process2) => {
227
+ return process2 && Object.prototype.hasOwnProperty.call(process2, prop);
228
+ };
229
+ try {
230
+ if (typeof process !== "undefined" && hasProperty(process.env)) {
231
+ return process.env[prop];
232
+ }
233
+ if (typeof import_meta !== "undefined" && hasProperty(import_meta.env)) {
234
+ return import_meta.env[prop];
235
+ }
236
+ if (typeof Deno !== "undefined" && Deno.env?.get) {
237
+ return Deno.env.get(prop);
238
+ }
239
+ if (typeof Bun !== "undefined" && hasProperty(Bun.env)) {
240
+ return Bun.env[prop];
241
+ }
242
+ const globalValue = globalThis[prop];
243
+ return typeof globalValue === "string" ? globalValue : void 0;
244
+ } catch {
245
+ return void 0;
246
+ }
247
+ }
248
+ });
249
+ var getEnv = (key) => {
250
+ const keys = [`AURA_AUTH_${key.toUpperCase()}`, `AURA_${key.toUpperCase()}`, `AUTH_${key.toUpperCase()}`, key.toUpperCase()];
251
+ return env[keys.find((k) => env[k]) ?? ""];
105
252
  };
106
- var toUpperCase = (str) => {
107
- return str.toUpperCase();
253
+
254
+ // src/assert.ts
255
+ var import_crypto = require("@aura-stack/jose/crypto");
256
+ var unsafeChars = [
257
+ "<",
258
+ ">",
259
+ '"',
260
+ "`",
261
+ " ",
262
+ "\r",
263
+ "\n",
264
+ " ",
265
+ "\\",
266
+ "%2F",
267
+ "%5C",
268
+ "%2f",
269
+ "%5c",
270
+ "\r\n",
271
+ "%0A",
272
+ "%0D",
273
+ "%0a",
274
+ "%0d",
275
+ "..",
276
+ "//",
277
+ "///",
278
+ "...",
279
+ "%20",
280
+ "\0"
281
+ ];
282
+ var isValidURL = (value) => {
283
+ if (!new RegExp(/^https?:\/\/[^/]/).test(value)) {
284
+ return false;
285
+ }
286
+ const match = value.match(/^(https?:\/\/)(.*)$/);
287
+ if (!match) return false;
288
+ const rest = match[2];
289
+ for (const char of unsafeChars) {
290
+ if (rest.includes(char)) return false;
291
+ }
292
+ const regex = /^https?:\/\/(?:[a-zA-Z0-9._-]+|localhost|\[[0-9a-fA-F:]+\])(?::\d{1,5})?(?:\/[a-zA-Z0-9._~!$&'()?#*+,;=:@-]*)*\/?$/;
293
+ return regex.test(match[0]);
108
294
  };
109
- var toCastCase = (obj, type = "snake") => {
110
- return Object.entries(obj).reduce((previous, [key, value]) => {
111
- const newKey = type === "snake" ? toSnakeCase(key) : toUpperCase(key);
112
- return { ...previous, [newKey]: value };
113
- }, {});
295
+ var isJWTPayloadWithToken = (payload) => {
296
+ return typeof payload === "object" && payload !== null && "token" in payload && typeof payload?.token === "string";
114
297
  };
115
- var equals = (a, b) => {
116
- if (a === null || b === null || a === void 0 || b === void 0) return false;
117
- return a === b;
298
+ var isRelativeURL = (value) => {
299
+ if (value.length > 100) return false;
300
+ for (const char of unsafeChars) {
301
+ if (value.includes(char)) return false;
302
+ }
303
+ const regex = /^\/[a-zA-Z0-9\-_\/.?&=#]*\/?$/;
304
+ return regex.test(value);
305
+ };
306
+ var isSameOrigin = (origin, expected) => {
307
+ const originURL = new URL(origin);
308
+ const expectedURL = new URL(expected);
309
+ return equals(originURL.origin, expectedURL.origin);
118
310
  };
119
- var sanitizeURL = (url) => {
311
+ var patternToRegex = (pattern) => {
120
312
  try {
121
- let decodedURL = decodeURIComponent(url).trim();
122
- const protocolMatch = decodedURL.match(/^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)/);
123
- let protocol = "";
124
- let rest = decodedURL;
125
- if (protocolMatch) {
126
- protocol = protocolMatch[1];
127
- rest = decodedURL.slice(protocol.length);
128
- const slashIndex = rest.indexOf("/");
129
- if (slashIndex === -1) {
130
- return protocol + rest;
131
- }
132
- const domain = rest.slice(0, slashIndex);
133
- let path = rest.slice(slashIndex).replace(/\/\.\.\//g, "/").replace(/\/\.\.$/, "").replace(/\.{2,}/g, "").replace(/\/{2,}/g, "/");
134
- if (path !== "/" && path.endsWith("/")) {
135
- path = path.replace(/\/+$/, "/");
136
- } else if (path !== "/") {
137
- path = path.replace(/\/+$/, "");
138
- }
139
- return protocol + domain + path;
140
- }
141
- let sanitized = decodedURL.replace(/\/\.\.\//g, "/").replace(/\/\.\.$/, "").replace(/\.{2,}/g, "").replace(/\/{2,}/g, "/");
142
- if (sanitized !== "/" && sanitized.endsWith("/")) {
143
- sanitized = sanitized.replace(/\/+$/, "/");
144
- } else if (sanitized !== "/") {
145
- sanitized = sanitized.replace(/\/+$/, "");
146
- }
147
- return sanitized;
313
+ if (pattern.length > 2048) return null;
314
+ pattern = pattern.replace(/\\/g, "");
315
+ const match = pattern.match(/^(https?):\/\/([a-zA-Z0-9.*-]{1,253})(?::(\d{1,5}|\*))?(?:\/.*)?$/);
316
+ if (!match) return null;
317
+ const [, protocol, host, port] = match;
318
+ const hasWildcard = host.includes("*");
319
+ if (hasWildcard && !host.startsWith("*.")) return null;
320
+ if (hasWildcard && host.slice(2).includes("*")) return null;
321
+ const domain = hasWildcard ? host.slice(2) : host;
322
+ const escapedDomain = domain.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
323
+ const hostRegex = hasWildcard ? `[^.]+\\.${escapedDomain}` : escapedDomain;
324
+ const portRegex = port === "*" ? ":\\d{1,5}" : port ? `:${port}` : "";
325
+ return new RegExp(`^${protocol}:\\/\\/${hostRegex}${portRegex}$`);
148
326
  } catch {
149
- return url.trim();
327
+ return null;
150
328
  }
151
329
  };
152
- var isValidRelativePath = (path) => {
153
- if (!path || typeof path !== "string") return false;
154
- if (!path.startsWith("/") || path.includes("://") || path.includes("\r") || path.includes("\n")) return false;
155
- if (/[\x00-\x1F\x7F]/.test(path) || path.includes("\0")) return false;
156
- const sanitized = sanitizeURL(path);
157
- if (sanitized.includes("..")) return false;
158
- return true;
159
- };
160
- var getNormalizedOriginPath = (path) => {
330
+ var isTrustedOrigin = (url, trustedOrigins) => {
331
+ if (!isValidURL(url) || trustedOrigins.length === 0) return false;
161
332
  try {
162
- const url = new URL(path);
163
- url.hash = "";
164
- url.search = "";
165
- return `${url.origin}${url.pathname}`;
333
+ const urlOrigin = new URL(url).origin;
334
+ for (const pattern of trustedOrigins) {
335
+ const regex = patternToRegex(pattern);
336
+ if (regex?.test(urlOrigin)) return true;
337
+ try {
338
+ if (isValidURL(pattern) && equals(new URL(pattern).origin, urlOrigin)) return true;
339
+ } catch {
340
+ }
341
+ }
166
342
  } catch {
167
- return sanitizeURL(path);
168
343
  }
344
+ return false;
345
+ };
346
+ var timingSafeEqual = (a, b) => {
347
+ const bufferA = import_crypto.encoder.encode(a);
348
+ const bufferB = import_crypto.encoder.encode(b);
349
+ const len = Math.max(bufferA.length, bufferB.length);
350
+ let diff = 0;
351
+ for (let i = 0; i < len; i++) {
352
+ diff |= (bufferA[i] ?? 0) ^ (bufferB[i] ?? 0);
353
+ }
354
+ return diff === 0 && bufferA.length === bufferB.length;
355
+ };
356
+
357
+ // src/utils.ts
358
+ var AURA_AUTH_VERSION = "0.4.0";
359
+ var equals = (a, b) => {
360
+ if (a === null || b === null || a === void 0 || b === void 0) return false;
361
+ return a === b;
362
+ };
363
+ var getBaseURL = (request) => {
364
+ const url = new URL(request.url);
365
+ return `${url.origin}${url.pathname}`;
169
366
  };
170
367
  var toISOString = (date) => {
171
368
  return new Date(date).toISOString();
172
369
  };
173
- var formatZodError = (error) => {
174
- if (!error.issues || error.issues.length === 0) {
175
- return {};
370
+ var extractPath = (url) => {
371
+ const pathRegex = /^https?:\/\/[a-zA-Z0-9_\-\.]+(:\d+)?(\/.*)$/;
372
+ const match = url.match(pathRegex);
373
+ return match && match[2] ? match[2] : "/";
374
+ };
375
+ var getErrorName = (error) => {
376
+ if (error instanceof Error) {
377
+ return error.name;
176
378
  }
177
- return error.issues.reduce((previous, issue) => {
178
- const key = issue.path.join(".");
179
- return {
180
- ...previous,
181
- [key]: {
182
- code: issue.code,
183
- message: issue.message
184
- }
185
- };
186
- }, {});
379
+ return typeof error === "string" ? error : "UnknownError";
187
380
  };
188
381
 
189
- // src/assert.ts
190
- var isValidURL = (value) => {
191
- if (value.includes("\r\n") || value.includes("\n") || value.includes("\r")) return false;
192
- const regex = /^https?:\/\/(?:[a-zA-Z0-9._-]+|localhost|\[[0-9a-fA-F:]+\])(?::\d{1,5})?(?:\/[a-zA-Z0-9._~!$&'()*+,;=:@-]*)*\/?$/;
193
- return regex.test(value);
194
- };
195
- var isJWTPayloadWithToken = (payload) => {
196
- return typeof payload === "object" && payload !== null && "token" in payload && typeof payload?.token === "string";
382
+ // src/jose.ts
383
+ var import_jose = require("@aura-stack/jose");
384
+ var import_jose2 = require("@aura-stack/jose/jose");
385
+ var import_crypto2 = require("@aura-stack/jose/crypto");
386
+ var jwtVerificationOptions = {
387
+ algorithms: ["HS256"],
388
+ typ: "JWT"
197
389
  };
198
390
 
199
391
  // src/secure.ts
200
392
  var generateSecure = (length = 32) => {
201
- return import_crypto.default.randomBytes(length).toString("base64url");
393
+ return import_jose2.base64url.encode((0, import_crypto2.getRandomBytes)(length));
202
394
  };
203
- var createHash = (data, base = "hex") => {
204
- return import_crypto.default.createHash("sha256").update(data).digest().toString(base);
395
+ var createSecretValue = (length = 32) => {
396
+ return import_jose2.base64url.encode((0, import_crypto2.getRandomBytes)(length));
397
+ };
398
+ var createHash = async (data) => {
399
+ const subtle = (0, import_crypto2.getSubtleCrypto)();
400
+ const digest = await subtle.digest("SHA-256", import_crypto2.encoder.encode(data));
401
+ return import_jose2.base64url.encode(new Uint8Array(digest));
205
402
  };
206
403
  var createPKCE = async (verifier) => {
207
- const codeVerifier = verifier ?? generateSecure(86);
208
- const codeChallenge = createHash(codeVerifier, "base64url");
404
+ const byteLength = verifier ? void 0 : Math.floor(Math.random() * (96 - 32 + 1) + 32);
405
+ const codeVerifier = verifier ?? generateSecure(byteLength ?? 64);
406
+ if (codeVerifier.length < 43 || codeVerifier.length > 128) {
407
+ throw new AuthSecurityError("PKCE_VERIFIER_INVALID", "The code verifier must be between 43 and 128 characters in length.");
408
+ }
409
+ const codeChallenge = await createHash(codeVerifier);
209
410
  return { codeVerifier, codeChallenge, method: "S256" };
210
411
  };
211
412
  var createCSRF = async (jose, csrfCookie) => {
212
413
  try {
213
414
  const token = generateSecure(32);
214
415
  if (csrfCookie) {
215
- await jose.verifyJWS(csrfCookie);
416
+ await jose.verifyJWS(csrfCookie, jwtVerificationOptions);
216
417
  return csrfCookie;
217
418
  }
218
419
  return jose.signJWS({ token });
@@ -223,20 +424,18 @@ var createCSRF = async (jose, csrfCookie) => {
223
424
  };
224
425
  var verifyCSRF = async (jose, cookie, header) => {
225
426
  try {
226
- const cookiePayload = await jose.verifyJWS(cookie);
227
- const headerPayload = await jose.verifyJWS(header);
427
+ const cookiePayload = await jose.verifyJWS(cookie, jwtVerificationOptions);
428
+ const headerPayload = await jose.verifyJWS(header, jwtVerificationOptions);
228
429
  if (!isJWTPayloadWithToken(cookiePayload)) {
229
430
  throw new AuthSecurityError("CSRF_TOKEN_INVALID", "Cookie payload missing token field.");
230
431
  }
231
432
  if (!isJWTPayloadWithToken(headerPayload)) {
232
433
  throw new AuthSecurityError("CSRF_TOKEN_INVALID", "Header payload missing token field.");
233
434
  }
234
- const cookieBuffer = Buffer.from(cookiePayload.token);
235
- const headerBuffer = Buffer.from(headerPayload.token);
236
- if (!equals(headerBuffer.length, cookieBuffer.length)) {
435
+ if (!equals(cookiePayload.token.length, headerPayload.token.length)) {
237
436
  throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
238
437
  }
239
- if (!import_crypto.default.timingSafeEqual(cookieBuffer, headerBuffer)) {
438
+ if (!timingSafeEqual(cookiePayload.token, headerPayload.token)) {
240
439
  throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
241
440
  }
242
441
  return true;
@@ -245,193 +444,244 @@ var verifyCSRF = async (jose, cookie, header) => {
245
444
  }
246
445
  };
247
446
 
248
- // src/schemas.ts
249
- var import_zod = require("zod");
250
- var OAuthProviderConfigSchema = (0, import_zod.object)({
251
- authorizeURL: (0, import_zod.string)().url(),
252
- accessToken: (0, import_zod.string)().url(),
253
- scope: (0, import_zod.string)().optional(),
254
- userInfo: (0, import_zod.string)().url(),
255
- responseType: (0, import_zod.enum)(["code", "token", "id_token"]),
256
- clientId: (0, import_zod.string)(),
257
- clientSecret: (0, import_zod.string)()
258
- });
259
- var OAuthAuthorization = OAuthProviderConfigSchema.extend({
260
- redirectURI: (0, import_zod.string)(),
261
- state: (0, import_zod.string)(),
262
- codeChallenge: (0, import_zod.string)(),
263
- codeChallengeMethod: (0, import_zod.enum)(["plain", "S256"])
264
- });
265
- var OAuthAuthorizationResponse = (0, import_zod.object)({
266
- state: (0, import_zod.string)({ message: "Missing state parameter in the OAuth authorization response." }),
267
- code: (0, import_zod.string)({ message: "Missing code parameter in the OAuth authorization response." })
268
- });
269
- var OAuthAuthorizationErrorResponse = (0, import_zod.object)({
270
- error: (0, import_zod.enum)([
271
- "invalid_request",
272
- "unauthorized_client",
273
- "access_denied",
274
- "unsupported_response_type",
275
- "invalid_scope",
276
- "server_error",
277
- "temporarily_unavailable"
278
- ]),
279
- error_description: (0, import_zod.string)().optional(),
280
- error_uri: (0, import_zod.string)().optional(),
281
- state: (0, import_zod.string)()
282
- });
283
- var OAuthAccessToken = OAuthProviderConfigSchema.extend({
284
- redirectURI: (0, import_zod.string)(),
285
- code: (0, import_zod.string)(),
286
- codeVerifier: (0, import_zod.string)().min(43).max(128)
287
- });
288
- var OAuthAccessTokenResponse = (0, import_zod.object)({
289
- access_token: (0, import_zod.string)(),
290
- token_type: (0, import_zod.string)().optional(),
291
- expires_in: (0, import_zod.number)().optional(),
292
- refresh_token: (0, import_zod.string)().optional(),
293
- scope: (0, import_zod.string)().optional().or((0, import_zod.null)())
294
- });
295
- var OAuthAccessTokenErrorResponse = (0, import_zod.object)({
296
- error: (0, import_zod.enum)([
297
- "invalid_request",
298
- "invalid_client",
299
- "invalid_grant",
300
- "unauthorized_client",
301
- "unsupported_grant_type",
302
- "invalid_scope"
303
- ]),
304
- error_description: (0, import_zod.string)().optional(),
305
- error_uri: (0, import_zod.string)().optional()
306
- });
307
- var OAuthErrorResponse = (0, import_zod.object)({
308
- error: (0, import_zod.string)(),
309
- error_description: (0, import_zod.string)().optional()
310
- });
311
- var OAuthEnvSchema = (0, import_zod.object)({
312
- clientId: import_zod.z.string().min(1, "OAuth Client ID is required in the environment variables."),
313
- clientSecret: import_zod.z.string().min(1, "OAuth Client Secret is required in the environment variables.")
314
- });
447
+ // src/actions/signIn/authorization-url.ts
448
+ var setSearchParams = (url, params) => {
449
+ for (const [key, value] of Object.entries(params)) {
450
+ if (value !== void 0 && value !== "") {
451
+ url.searchParams.set(key, value);
452
+ }
453
+ }
454
+ };
455
+ var buildAuthorizationURL = (oauth, redirect_uri, state, code_challenge, code_challenge_method) => {
456
+ const authorizeConfig = oauth.authorize;
457
+ const baseURL = typeof authorizeConfig === "string" ? authorizeConfig : authorizeConfig?.url ?? oauth.authorizeURL;
458
+ if (!baseURL) {
459
+ throw new AuthInternalError("INVALID_OAUTH_CONFIGURATION", "Missing authorization URL in OAuth provider configuration.");
460
+ }
461
+ const url = new URL(baseURL);
462
+ const authorizeParams = typeof authorizeConfig === "string" ? void 0 : authorizeConfig?.params;
463
+ setSearchParams(url, {
464
+ response_type: authorizeParams?.responseType ?? oauth.responseType ?? "code",
465
+ client_id: oauth.clientId,
466
+ redirect_uri,
467
+ state,
468
+ code_challenge,
469
+ code_challenge_method,
470
+ scope: authorizeParams?.scope ?? oauth.scope,
471
+ prompt: authorizeParams?.prompt,
472
+ response_mode: authorizeParams?.responseMode,
473
+ login_hint: authorizeParams?.loginHint,
474
+ nonce: authorizeParams?.nonce,
475
+ display: authorizeParams?.display,
476
+ audience: authorizeParams?.audience
477
+ });
478
+ return url.toString();
479
+ };
480
+ var createAuthorizationURL = async (oauth, redirectURI, ctx) => {
481
+ const state = createSecretValue();
482
+ const { codeVerifier, codeChallenge, method } = await createPKCE();
483
+ const authorization = buildAuthorizationURL(oauth, redirectURI, state, codeChallenge, method);
484
+ const parsed = OAuthAuthorization.safeParse({ ...oauth, redirectURI, state, codeChallenge, codeChallengeMethod: method });
485
+ if (!parsed.success) {
486
+ ctx?.logger?.log("INVALID_OAUTH_CONFIGURATION", {
487
+ structuredData: {
488
+ scope: oauth?.scope ?? "",
489
+ redirect_uri: redirectURI,
490
+ has_state: Boolean(state),
491
+ has_code_challenge: Boolean(codeChallenge),
492
+ code_challenge_method: method
493
+ }
494
+ });
495
+ throw new AuthInternalError("INVALID_OAUTH_CONFIGURATION", "The OAuth provider configuration is invalid.");
496
+ }
497
+ return {
498
+ authorization,
499
+ state,
500
+ codeVerifier,
501
+ method
502
+ };
503
+ };
315
504
 
316
505
  // src/actions/signIn/authorization.ts
317
- var createAuthorizationURL = (oauthConfig, redirectURI, state, codeChallenge, codeChallengeMethod) => {
318
- const parsed = OAuthAuthorization.safeParse({ ...oauthConfig, redirectURI, state, codeChallenge, codeChallengeMethod });
319
- if (!parsed.success) {
320
- const msg = JSON.stringify(formatZodError(parsed.error), null, 2);
321
- throw new AuthInternalError("INVALID_OAUTH_CONFIGURATION", msg);
322
- }
323
- const { authorizeURL, ...options2 } = parsed.data;
324
- const { userInfo, accessToken, clientSecret, ...required } = options2;
325
- const searchParams = new URLSearchParams(toCastCase(required));
326
- return `${authorizeURL}?${searchParams}`;
327
- };
328
- var getOriginURL = (request, trustedProxyHeaders) => {
329
- const headers = request.headers;
330
- if (trustedProxyHeaders) {
331
- const protocol = headers.get("X-Forwarded-Proto") ?? headers.get("Forwarded")?.match(/proto=([^;]+)/i)?.[1] ?? "http";
332
- const host = headers.get("X-Forwarded-Host") ?? headers.get("Host") ?? headers.get("Forwarded")?.match(/host=([^;]+)/i)?.[1] ?? null;
333
- return new URL(`${protocol}://${host}${getNormalizedOriginPath(new URL(request.url).pathname)}`);
334
- } else {
335
- return new URL(getNormalizedOriginPath(request.url));
506
+ var getTrustedOrigins = async (request, trustedOrigins) => {
507
+ if (!trustedOrigins) return [];
508
+ const raw = typeof trustedOrigins === "function" ? await trustedOrigins(request) : trustedOrigins;
509
+ return Array.isArray(raw) ? raw : typeof raw === "string" ? [raw] : [];
510
+ };
511
+ var getBaseURL2 = async ({
512
+ ctx,
513
+ request,
514
+ headers: headersInit
515
+ }) => {
516
+ const origin = getEnv("BASE_URL") || ctx?.baseURL;
517
+ if (origin && origin !== "/") return origin;
518
+ if (ctx?.trustedProxyHeaders) {
519
+ const headers = headersInit && new Headers(headersInit) || request?.headers;
520
+ const protocol = headers?.get("Forwarded")?.match(/proto=([^;]+)/i)?.[1] ?? headers?.get("X-Forwarded-Proto") ?? "http";
521
+ const host = headers?.get("Host") ?? headers?.get("Forwarded")?.match(/host=([^;]+)/i)?.[1] ?? headers?.get("X-Forwarded-Host") ?? null;
522
+ if (host) return `${protocol}://${host}`;
523
+ throw new AuthInternalError(
524
+ "INVALID_OAUTH_CONFIGURATION",
525
+ "The URL cannot be constructed. Please set the BASE_URL environment variable or provide trusted proxy host headers."
526
+ );
527
+ }
528
+ try {
529
+ return new URL(request?.url ?? "not-found").origin;
530
+ } catch (error) {
531
+ throw new AuthInternalError(
532
+ "INVALID_OAUTH_CONFIGURATION",
533
+ "The URL cannot be constructed. Please set the BASE_URL environment variable or enable trustedProxyHeaders.",
534
+ { cause: error }
535
+ );
336
536
  }
337
537
  };
338
- var createRedirectURI = (request, oauth, basePath, trustedProxyHeaders) => {
339
- const url = getOriginURL(request, trustedProxyHeaders);
340
- return `${url.origin}${basePath}/callback/${oauth}`;
538
+ var getOriginURL = async (request, context) => {
539
+ const trustedOrigins = await getTrustedOrigins(request, context?.trustedOrigins);
540
+ trustedOrigins.push(new URL(request.url).origin);
541
+ const origin = await getBaseURL2({ request, ctx: context });
542
+ if (!isTrustedOrigin(origin, trustedOrigins)) {
543
+ context?.logger?.log("UNTRUSTED_ORIGIN", { structuredData: { origin } });
544
+ throw new AuthInternalError("UNTRUSTED_ORIGIN", "The constructed origin URL is not trusted.");
545
+ }
546
+ return origin;
547
+ };
548
+ var createRedirectURI = async (request, oauth, context) => {
549
+ const origin = await getOriginURL(request, context);
550
+ return `${origin}${context.basePath}/callback/${oauth}`;
341
551
  };
342
- var createRedirectTo = (request, redirectTo, trustedProxyHeaders) => {
552
+ var createSignInURL = async ({
553
+ request,
554
+ oauth,
555
+ ctx,
556
+ redirectTo
557
+ }) => {
558
+ const origin = await getOriginURL(request, ctx);
559
+ const searchParams = new URLSearchParams();
560
+ if (redirectTo !== void 0) searchParams.set("redirectTo", String(redirectTo));
561
+ return `${origin}${ctx.basePath}/signIn/${oauth}?${searchParams.toString()}`;
562
+ };
563
+ var createRedirectTo = async (request, redirectTo, context) => {
343
564
  try {
344
565
  const headers = request.headers;
345
- const origin = headers.get("Origin");
346
- const referer = headers.get("Referer");
347
- let hostedURL = getOriginURL(request, trustedProxyHeaders);
348
- if (redirectTo) {
349
- if (redirectTo.startsWith("/")) {
350
- return sanitizeURL(redirectTo);
351
- }
352
- const redirectToURL = new URL(sanitizeURL(getNormalizedOriginPath(redirectTo)));
353
- if (!isValidURL(redirectTo) || !equals(redirectToURL.origin, hostedURL.origin)) {
354
- throw new AuthSecurityError(
355
- "POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
356
- "The redirectTo parameter does not match the hosted origin."
357
- );
566
+ const requestOrigin = await getOriginURL(request, context);
567
+ const origins = await getTrustedOrigins(request, context?.trustedOrigins);
568
+ const validateURL = (url) => {
569
+ if (!isRelativeURL(url) && !isValidURL(url)) return "/";
570
+ if (isRelativeURL(url)) return url;
571
+ if (origins.length > 0) {
572
+ if (isTrustedOrigin(url, origins)) {
573
+ const urlOrigin = new URL(url).origin;
574
+ for (const pattern of origins) {
575
+ const regex = patternToRegex(pattern);
576
+ if (regex?.test(urlOrigin)) {
577
+ return isSameOrigin(url, request.url) ? extractPath(url) : url;
578
+ }
579
+ if (isValidURL(pattern) && equals(new URL(pattern).origin, urlOrigin)) return url;
580
+ }
581
+ }
582
+ context?.logger?.log("OPEN_REDIRECT_ATTACK");
583
+ return "/";
358
584
  }
359
- return sanitizeURL(redirectToURL.pathname);
360
- }
361
- if (referer) {
362
- const refererURL = new URL(sanitizeURL(referer));
363
- if (!isValidURL(referer) || !equals(refererURL.origin, hostedURL.origin)) {
364
- throw new AuthSecurityError(
365
- "POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
366
- "The referer of the request does not match the hosted origin."
367
- );
585
+ if (isSameOrigin(url, requestOrigin)) {
586
+ return extractPath(url);
368
587
  }
369
- return sanitizeURL(refererURL.pathname);
370
- }
371
- if (origin) {
372
- const originURL = new URL(sanitizeURL(getNormalizedOriginPath(origin)));
373
- if (!isValidURL(origin) || !equals(originURL.origin, hostedURL.origin)) {
374
- throw new AuthSecurityError("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", "Invalid origin (potential CSRF).");
375
- }
376
- return sanitizeURL(originURL.pathname);
377
- }
378
- return "/";
588
+ context?.logger?.log("OPEN_REDIRECT_ATTACK");
589
+ return "/";
590
+ };
591
+ return validateURL(redirectTo ?? headers.get("Referer") ?? headers.get("Origin") ?? "/");
379
592
  } catch (error) {
380
- if (isAuthSecurityError(error)) {
381
- throw error;
382
- }
383
- throw new AuthSecurityError("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", "Invalid origin (potential CSRF).");
593
+ context?.logger?.log("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED");
594
+ return "/";
384
595
  }
385
596
  };
386
597
 
598
+ // src/api/signIn.ts
599
+ var signIn = async (oauth, {
600
+ ctx,
601
+ headers: headersInit,
602
+ redirectTo = "/",
603
+ redirect,
604
+ request: requestInit
605
+ }) => {
606
+ const headers = new Headers(headersInit);
607
+ const provider = ctx.oauth[oauth];
608
+ if (!provider) {
609
+ throw new AuthInternalError("INVALID_OAUTH_CONFIGURATION", `The OAuth provider "${oauth}" is not configured.`);
610
+ }
611
+ let request = requestInit;
612
+ if (!request) {
613
+ const origin = await getBaseURL2({ ctx, headers });
614
+ const url = `${origin}${ctx.basePath}/signIn/${oauth}`;
615
+ request = new Request(url, { headers });
616
+ }
617
+ if (redirect === false) {
618
+ const signInURL = await createSignInURL({ request, oauth, ctx, redirectTo });
619
+ return { redirect: false, signInURL };
620
+ }
621
+ const redirectURI = await createRedirectURI(request, oauth, ctx);
622
+ const redirectToValue = await createRedirectTo(request, redirectTo, ctx);
623
+ const { authorization, state, codeVerifier } = await createAuthorizationURL(provider, redirectURI, ctx);
624
+ ctx?.logger?.log("SIGN_IN_INITIATED", {
625
+ structuredData: { oauth_provider: oauth }
626
+ });
627
+ const headersList = new import_router2.HeadersBuilder(cacheControl).setHeader("Location", authorization).setCookie(ctx.cookies.state.name, state, ctx.cookies.state.attributes).setCookie(ctx.cookies.redirectURI.name, redirectURI, ctx.cookies.redirectURI.attributes).setCookie(ctx.cookies.redirectTo.name, redirectToValue, ctx.cookies.redirectTo.attributes).setCookie(ctx.cookies.codeVerifier.name, codeVerifier, ctx.cookies.codeVerifier.attributes).toHeaders();
628
+ return Response.json(
629
+ { redirect: redirect ?? true, signInURL: authorization },
630
+ {
631
+ status: redirect ?? true ? 302 : 200,
632
+ headers: headersList
633
+ }
634
+ );
635
+ };
636
+
387
637
  // src/actions/signIn/signIn.ts
638
+ var import_router3 = require("@aura-stack/router");
388
639
  var signInConfig = (oauth) => {
389
- return (0, import_router2.createEndpointConfig)("/signIn/:oauth", {
640
+ return (0, import_router3.createEndpointConfig)("/signIn/:oauth", {
390
641
  schemas: {
391
- params: import_zod2.z.object({
392
- oauth: import_zod2.z.enum(
642
+ params: import_v42.z.object({
643
+ oauth: import_v42.z.enum(
393
644
  Object.keys(oauth),
394
645
  "The OAuth provider is not supported or invalid."
395
646
  )
396
647
  }),
397
- searchParams: import_zod2.z.object({
398
- redirectTo: import_zod2.z.string().optional()
648
+ searchParams: import_v42.z.object({
649
+ redirect: import_v42.z.stringbool().optional().default(true),
650
+ redirectTo: import_v42.z.string().optional()
399
651
  })
400
652
  }
401
653
  });
402
654
  };
403
655
  var signInAction = (oauth) => {
404
- return (0, import_router2.createEndpoint)(
656
+ return (0, import_router3.createEndpoint)(
405
657
  "GET",
406
658
  "/signIn/:oauth",
407
659
  async (ctx) => {
408
660
  const {
409
661
  request,
410
662
  params: { oauth: oauth2 },
411
- searchParams: { redirectTo },
412
- context: { oauth: providers, cookies, trustedProxyHeaders, basePath }
663
+ searchParams: { redirectTo, redirect },
664
+ context
413
665
  } = ctx;
414
- const state = generateSecure();
415
- const redirectURI = createRedirectURI(request, oauth2, basePath, trustedProxyHeaders);
416
- const redirectToValue = createRedirectTo(request, redirectTo, trustedProxyHeaders);
417
- const { codeVerifier, codeChallenge, method } = await createPKCE();
418
- const authorization = createAuthorizationURL(providers[oauth2], redirectURI, state, codeChallenge, method);
419
- const headers = new import_router2.HeadersBuilder(cacheControl).setHeader("Location", authorization).setCookie(cookies.state.name, state, cookies.state.attributes).setCookie(cookies.redirectURI.name, redirectURI, cookies.redirectURI.attributes).setCookie(cookies.redirectTo.name, redirectToValue, cookies.redirectTo.attributes).setCookie(cookies.codeVerifier.name, codeVerifier, cookies.codeVerifier.attributes).toHeaders();
420
- return Response.json(
421
- { oauth: oauth2 },
422
- {
423
- status: 302,
424
- headers
425
- }
426
- );
666
+ const signInResult = await signIn(oauth2, {
667
+ ctx: context,
668
+ headers: request.headers,
669
+ redirect,
670
+ redirectTo,
671
+ request
672
+ });
673
+ if (!redirect) {
674
+ return Response.json(signInResult, { status: 200 });
675
+ }
676
+ return signInResult;
427
677
  },
428
678
  signInConfig(oauth)
429
679
  );
430
680
  };
431
681
 
432
682
  // src/actions/callback/callback.ts
433
- var import_zod3 = require("zod");
434
- var import_router3 = require("@aura-stack/router");
683
+ var import_v43 = require("zod/v4");
684
+ var import_router4 = require("@aura-stack/router");
435
685
 
436
686
  // src/request.ts
437
687
  var fetchAsync = async (url, options2 = {}, timeout = 5e3) => {
@@ -454,71 +704,127 @@ var getDefaultUserInfo = (profile) => {
454
704
  image: profile?.image ?? profile?.picture
455
705
  };
456
706
  };
457
- var getUserInfo = async (oauthConfig, accessToken) => {
458
- const userinfoEndpoint = oauthConfig.userInfo;
707
+ var getUserInfo = async (oauthConfig, accessToken, logger) => {
708
+ const userInfoConfig = oauthConfig.userInfo;
709
+ const userinfoURL = typeof userInfoConfig === "string" ? userInfoConfig : userInfoConfig.url;
710
+ const extraHeaders = typeof userInfoConfig === "string" ? void 0 : userInfoConfig.headers;
711
+ const method = typeof userInfoConfig === "string" ? "GET" : (userInfoConfig.method ?? "GET").toUpperCase();
459
712
  try {
460
- const response = await fetchAsync(userinfoEndpoint, {
461
- method: "GET",
713
+ logger?.log("OAUTH_USERINFO_REQUEST_INITIATED", {
714
+ structuredData: {
715
+ endpoint: userinfoURL
716
+ }
717
+ });
718
+ const response = await fetchAsync(userinfoURL, {
719
+ method,
462
720
  headers: {
721
+ "User-Agent": `Aura Auth/${AURA_AUTH_VERSION}`,
463
722
  Accept: "application/json",
464
- Authorization: `Bearer ${accessToken}`
723
+ Authorization: `Bearer ${accessToken}`,
724
+ ...extraHeaders ?? {}
465
725
  }
466
726
  });
727
+ if (!response.ok) {
728
+ logger?.log("OAUTH_USERINFO_INVALID_RESPONSE");
729
+ throw new OAuthProtocolError("INVALID_REQUEST", "Invalid userinfo response format");
730
+ }
467
731
  const json = await response.json();
468
732
  const { success, data } = OAuthErrorResponse.safeParse(json);
469
733
  if (success) {
470
- throw new OAuthProtocolError(
471
- data.error,
472
- data?.error_description ?? "An error occurred while fetching user information."
473
- );
734
+ logger?.log("OAUTH_USERINFO_ERROR", {
735
+ message: "Error response received from OAuth userinfo endpoint",
736
+ structuredData: {
737
+ error: data.error,
738
+ error_description: data.error_description ?? ""
739
+ }
740
+ });
741
+ throw new OAuthProtocolError("INVALID_REQUEST", "An error was received from the OAuth userinfo endpoint.");
474
742
  }
743
+ logger?.log("OAUTH_USERINFO_SUCCESS");
475
744
  return oauthConfig?.profile ? oauthConfig.profile(json) : getDefaultUserInfo(json);
476
745
  } catch (error) {
477
746
  if (isOAuthProtocolError(error)) {
478
747
  throw error;
479
748
  }
749
+ logger?.log("OAUTH_USERINFO_REQUEST_FAILED");
480
750
  if (isNativeError(error)) {
481
- throw new OAuthProtocolError("invalid_request", error.message, "", { cause: error });
751
+ throw new OAuthProtocolError("SERVER_ERROR", "Failed to fetch user information from OAuth provider", "", {
752
+ cause: error
753
+ });
482
754
  }
483
- throw new OAuthProtocolError("invalid_request", "Failed to fetch user information.", "", { cause: error });
755
+ throw new OAuthProtocolError("SERVER_ERROR", "Failed to fetch user information", "", { cause: error });
484
756
  }
485
757
  };
486
758
 
487
759
  // src/actions/callback/access-token.ts
488
- var createAccessToken = async (oauthConfig, redirectURI, code, codeVerifier) => {
489
- const parsed = OAuthAccessToken.safeParse({ ...oauthConfig, redirectURI, code, codeVerifier });
490
- if (!parsed.success) {
491
- const msg = JSON.stringify(formatZodError(parsed.error), null, 2);
492
- throw new AuthInternalError("INVALID_OAUTH_CONFIGURATION", msg);
760
+ var createAccessToken = async (oauthConfig, redirectURI, code, codeVerifier, logger) => {
761
+ const { accessToken, clientId, clientSecret } = oauthConfig;
762
+ if (!clientId || !clientSecret || !redirectURI || !code || !codeVerifier || !accessToken) {
763
+ logger?.log("INVALID_OAUTH_CONFIGURATION", {
764
+ structuredData: {
765
+ has_client_id: Boolean(clientId),
766
+ has_client_secret: Boolean(clientSecret),
767
+ has_access_token: Boolean(accessToken),
768
+ has_redirect_uri: Boolean(redirectURI),
769
+ has_code: Boolean(code),
770
+ has_code_verifier: Boolean(codeVerifier)
771
+ }
772
+ });
773
+ throw new AuthInternalError("INVALID_OAUTH_CONFIGURATION", "The OAuth provider configuration is invalid.");
493
774
  }
494
- const { accessToken, clientId, clientSecret, code: codeParsed, redirectURI: redirectParsed } = parsed.data;
775
+ const tokenURL = typeof accessToken === "string" ? accessToken : accessToken.url;
776
+ const extraHeaders = typeof accessToken === "string" ? void 0 : accessToken.headers;
495
777
  try {
496
- const response = await fetchAsync(accessToken, {
778
+ logger?.log("OAUTH_ACCESS_TOKEN_REQUEST_INITIATED", {
779
+ structuredData: {
780
+ has_client_id: Boolean(clientId),
781
+ redirect_uri: redirectURI,
782
+ grant_type: "authorization_code"
783
+ }
784
+ });
785
+ const response = await fetchAsync(tokenURL, {
497
786
  method: "POST",
498
787
  headers: {
788
+ ...extraHeaders ?? {},
499
789
  Accept: "application/json",
500
790
  "Content-Type": "application/x-www-form-urlencoded"
501
791
  },
502
792
  body: new URLSearchParams({
503
793
  client_id: clientId,
504
794
  client_secret: clientSecret,
505
- code: codeParsed,
506
- redirect_uri: redirectParsed,
795
+ code,
796
+ redirect_uri: redirectURI,
507
797
  grant_type: "authorization_code",
508
798
  code_verifier: codeVerifier
509
799
  }).toString()
510
800
  });
801
+ if (!response.ok) {
802
+ logger?.log("INVALID_OAUTH_ACCESS_TOKEN_RESPONSE");
803
+ throw new OAuthProtocolError("invalid_request", "Invalid access token response");
804
+ }
511
805
  const json = await response.json();
512
806
  const token = OAuthAccessTokenResponse.safeParse(json);
513
807
  if (!token.success) {
514
808
  const { success, data } = OAuthAccessTokenErrorResponse.safeParse(json);
515
809
  if (!success) {
516
- throw new OAuthProtocolError("INVALID_REQUEST", "Invalid access token response format");
810
+ logger?.log("INVALID_OAUTH_ACCESS_TOKEN_RESPONSE");
811
+ throw new OAuthProtocolError("invalid_request", "Invalid access token response format");
517
812
  }
518
- throw new OAuthProtocolError(data.error, data?.error_description ?? "Failed to retrieve access token");
813
+ logger?.log("OAUTH_ACCESS_TOKEN_ERROR", {
814
+ structuredData: {
815
+ error: data.error,
816
+ error_description: data.error_description ?? ""
817
+ }
818
+ });
819
+ throw new OAuthProtocolError("INVALID_ACCESS_TOKEN", "Failed to retrieve access token");
519
820
  }
821
+ logger?.log("OAUTH_ACCESS_TOKEN_SUCCESS");
520
822
  return token.data;
521
823
  } catch (error) {
824
+ logger?.log("OAUTH_ACCESS_TOKEN_REQUEST_FAILED");
825
+ if (error instanceof Error) {
826
+ throw new OAuthProtocolError("server_error", "Failed to communicate with OAuth provider", "", { cause: error });
827
+ }
522
828
  throw error;
523
829
  }
524
830
  };
@@ -543,10 +849,11 @@ var setCookie = (cookieName, value, options2) => {
543
849
  var expiredCookieAttributes = {
544
850
  ...defaultCookieOptions,
545
851
  expires: /* @__PURE__ */ new Date(0),
546
- maxAge: 0
852
+ maxAge: 0,
853
+ secure: true
547
854
  };
548
855
  var getCookie = (request, cookieName) => {
549
- const cookies = request.headers.get("Cookie");
856
+ const cookies = request instanceof Request ? request.headers.get("Cookie") : request.get("Cookie");
550
857
  if (!cookies) {
551
858
  throw new AuthInternalError("COOKIE_NOT_FOUND", "No cookies found. There is no active session");
552
859
  }
@@ -567,25 +874,38 @@ var createSessionCookie = async (jose, session) => {
567
874
 
568
875
  // src/actions/callback/callback.ts
569
876
  var callbackConfig = (oauth) => {
570
- return (0, import_router3.createEndpointConfig)("/callback/:oauth", {
877
+ return (0, import_router4.createEndpointConfig)("/callback/:oauth", {
571
878
  schemas: {
572
- params: import_zod3.z.object({
573
- oauth: import_zod3.z.enum(
879
+ params: import_v43.z.object({
880
+ oauth: import_v43.z.enum(
574
881
  Object.keys(oauth),
575
882
  "The OAuth provider is not supported or invalid."
576
883
  )
577
884
  }),
578
- searchParams: import_zod3.z.object({
579
- code: import_zod3.z.string("Missing code parameter in the OAuth authorization response."),
580
- state: import_zod3.z.string("Missing state parameter in the OAuth authorization response.")
885
+ searchParams: import_v43.z.object({
886
+ code: import_v43.z.string("Missing code parameter in the OAuth authorization response."),
887
+ state: import_v43.z.string("Missing state parameter in the OAuth authorization response.")
581
888
  })
582
889
  },
583
- middlewares: [
890
+ use: [
584
891
  (ctx) => {
585
- const response = OAuthAuthorizationErrorResponse.safeParse(ctx.searchParams);
892
+ const {
893
+ searchParams,
894
+ context: { logger }
895
+ } = ctx;
896
+ const response = OAuthAuthorizationErrorResponse.safeParse(searchParams);
586
897
  if (response.success) {
587
898
  const { error, error_description } = response.data;
588
- throw new OAuthProtocolError(error, error_description ?? "OAuth Authorization Error");
899
+ const criticalAuthErrors = ["access_denied", "server_error"];
900
+ const severity = criticalAuthErrors.includes(error.toLowerCase()) ? "critical" : "warning";
901
+ logger?.log("OAUTH_AUTHORIZATION_ERROR", {
902
+ severity,
903
+ structuredData: {
904
+ error,
905
+ error_description: error_description ?? ""
906
+ }
907
+ });
908
+ throw new OAuthProtocolError(error, error_description || "OAuth Authorization Error");
589
909
  }
590
910
  return ctx;
591
911
  }
@@ -593,7 +913,7 @@ var callbackConfig = (oauth) => {
593
913
  });
594
914
  };
595
915
  var callbackAction = (oauth) => {
596
- return (0, import_router3.createEndpoint)(
916
+ return (0, import_router4.createEndpoint)(
597
917
  "GET",
598
918
  "/callback/:oauth",
599
919
  async (ctx) => {
@@ -601,31 +921,54 @@ var callbackAction = (oauth) => {
601
921
  request,
602
922
  params: { oauth: oauth2 },
603
923
  searchParams: { code, state },
604
- context: { oauth: providers, cookies, jose }
924
+ context
605
925
  } = ctx;
926
+ const { oauth: providers, cookies, jose, logger, trustedOrigins } = context;
606
927
  const oauthConfig = providers[oauth2];
607
928
  const cookieState = getCookie(request, cookies.state.name);
929
+ const codeVerifier = getCookie(request, cookies.codeVerifier.name);
608
930
  const cookieRedirectTo = getCookie(request, cookies.redirectTo.name);
609
931
  const cookieRedirectURI = getCookie(request, cookies.redirectURI.name);
610
- const codeVerifier = getCookie(request, cookies.codeVerifier.name);
611
- if (!equals(cookieState, state)) {
932
+ if (!timingSafeEqual(cookieState, state)) {
933
+ logger?.log("MISMATCHING_STATE", {
934
+ structuredData: {
935
+ oauth_provider: oauth2
936
+ }
937
+ });
612
938
  throw new AuthSecurityError(
613
939
  "MISMATCHING_STATE",
614
940
  "The provided state passed in the OAuth response does not match the stored state."
615
941
  );
616
942
  }
617
- const accessToken = await createAccessToken(oauthConfig, cookieRedirectURI, code, codeVerifier);
618
- const sanitized = sanitizeURL(cookieRedirectTo);
619
- if (!isValidRelativePath(sanitized)) {
620
- throw new AuthSecurityError(
621
- "POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
622
- "Invalid redirect path. Potential open redirect attack detected."
623
- );
943
+ const accessToken = await createAccessToken(oauthConfig, cookieRedirectURI, code, codeVerifier, logger);
944
+ const origins = await getTrustedOrigins(request, trustedOrigins);
945
+ const requestOrigin = await getOriginURL(request, context);
946
+ if (!isRelativeURL(cookieRedirectTo)) {
947
+ const isValid = origins.length > 0 ? isTrustedOrigin(cookieRedirectTo, origins) : isSameOrigin(cookieRedirectTo, requestOrigin);
948
+ if (!isValid) {
949
+ logger?.log("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", {
950
+ structuredData: {
951
+ redirect_path: cookieRedirectTo,
952
+ provider: oauth2,
953
+ has_trusted_origins: origins.length > 0,
954
+ request_origin: requestOrigin
955
+ }
956
+ });
957
+ throw new AuthSecurityError(
958
+ "POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
959
+ "Invalid redirect path. Potential open redirect attack detected."
960
+ );
961
+ }
624
962
  }
625
- const userInfo = await getUserInfo(oauthConfig, accessToken.access_token);
963
+ const userInfo = await getUserInfo(oauthConfig, accessToken.access_token, logger);
626
964
  const sessionCookie = await createSessionCookie(jose, userInfo);
627
965
  const csrfToken = await createCSRF(jose);
628
- const headers = new import_router3.HeadersBuilder(cacheControl).setHeader("Location", sanitized).setCookie(cookies.sessionToken.name, sessionCookie, cookies.sessionToken.attributes).setCookie(cookies.csrfToken.name, csrfToken, cookies.csrfToken.attributes).setCookie(cookies.state.name, "", expiredCookieAttributes).setCookie(cookies.redirectURI.name, "", expiredCookieAttributes).setCookie(cookies.redirectTo.name, "", expiredCookieAttributes).setCookie(cookies.codeVerifier.name, "", expiredCookieAttributes).toHeaders();
966
+ logger?.log("OAUTH_CALLBACK_SUCCESS", {
967
+ structuredData: {
968
+ provider: oauth2
969
+ }
970
+ });
971
+ const headers = new import_router4.HeadersBuilder(cacheControl).setHeader("Location", cookieRedirectTo).setCookie(cookies.sessionToken.name, sessionCookie, cookies.sessionToken.attributes).setCookie(cookies.csrfToken.name, csrfToken, cookies.csrfToken.attributes).setCookie(cookies.state.name, "", expiredCookieAttributes).setCookie(cookies.redirectURI.name, "", expiredCookieAttributes).setCookie(cookies.redirectTo.name, "", expiredCookieAttributes).setCookie(cookies.codeVerifier.name, "", expiredCookieAttributes).toHeaders();
629
972
  return Response.json({ oauth: oauth2 }, { status: 302, headers });
630
973
  },
631
974
  callbackConfig(oauth)
@@ -633,74 +976,161 @@ var callbackAction = (oauth) => {
633
976
  };
634
977
 
635
978
  // src/actions/session/session.ts
636
- var import_router4 = require("@aura-stack/router");
637
- var sessionAction = (0, import_router4.createEndpoint)("GET", "/session", async (ctx) => {
979
+ var import_router5 = require("@aura-stack/router");
980
+
981
+ // src/api/getSession.ts
982
+ var getSession = async ({ ctx, headers }) => {
983
+ try {
984
+ const session = getCookie(new Headers(headers), ctx.cookies.sessionToken.name);
985
+ const decoded = await ctx.jose.decodeJWT(session);
986
+ ctx?.logger?.log("AUTH_SESSION_VALID");
987
+ const { exp, iat, jti, nbf, aud, iss, ...user } = decoded;
988
+ return {
989
+ session: {
990
+ user,
991
+ expires: toISOString(exp * 1e3)
992
+ },
993
+ authenticated: true
994
+ };
995
+ } catch (error) {
996
+ ctx?.logger?.log("AUTH_SESSION_INVALID", { structuredData: { error_type: getErrorName(error) } });
997
+ return { session: null, authenticated: false };
998
+ }
999
+ };
1000
+
1001
+ // src/actions/session/session.ts
1002
+ var sessionAction = (0, import_router5.createEndpoint)("GET", "/session", async (ctx) => {
638
1003
  const {
639
1004
  request,
640
- context: { jose, cookies }
1005
+ context: { cookies }
641
1006
  } = ctx;
642
1007
  try {
643
- const session = getCookie(request, cookies.sessionToken.name);
644
- const decoded = await jose.decodeJWT(session);
645
- const { exp, iat, jti, nbf, ...user } = decoded;
646
- const headers = new Headers(cacheControl);
647
- return Response.json({ user, expires: toISOString(exp * 1e3) }, { headers });
1008
+ const session = await getSession({ ctx: ctx.context, headers: request.headers });
1009
+ if (!session.authenticated) {
1010
+ throw new AuthInternalError("INVALID_JWT_TOKEN", "Session not authenticated");
1011
+ }
1012
+ return Response.json(session, { headers: secureApiHeaders });
648
1013
  } catch (error) {
649
- const headers = new import_router4.HeadersBuilder(cacheControl).setCookie(cookies.sessionToken.name, "", expiredCookieAttributes).toHeaders();
650
- return Response.json({ authenticated: false, message: "Unauthorized" }, { status: 401, headers });
1014
+ const headers = new import_router5.HeadersBuilder(secureApiHeaders).setCookie(cookies.sessionToken.name, "", expiredCookieAttributes).toHeaders();
1015
+ return Response.json({ session: null, authenticated: false }, { status: 401, headers });
651
1016
  }
652
1017
  });
653
1018
 
654
1019
  // src/actions/signOut/signOut.ts
655
- var import_zod4 = require("zod");
656
- var import_router5 = require("@aura-stack/router");
657
- var config = (0, import_router5.createEndpointConfig)({
1020
+ var import_v44 = require("zod/v4");
1021
+ var import_router7 = require("@aura-stack/router");
1022
+
1023
+ // src/api/signOut.ts
1024
+ var import_router6 = require("@aura-stack/router");
1025
+ var signOut = async ({
1026
+ ctx,
1027
+ headers: headersInit,
1028
+ redirectTo = "/",
1029
+ skipCSRFCheck = false
1030
+ }) => {
1031
+ const headers = new Headers(headersInit);
1032
+ const header = headers.get("X-CSRF-Token");
1033
+ let session = null;
1034
+ let csrfToken = null;
1035
+ try {
1036
+ session = getCookie(headers, ctx.cookies.sessionToken.name);
1037
+ } catch {
1038
+ throw new AuthSecurityError("SESSION_TOKEN_MISSING", "The sessionToken is missing.");
1039
+ }
1040
+ try {
1041
+ csrfToken = getCookie(headers, ctx.cookies.csrfToken.name);
1042
+ } catch {
1043
+ throw new AuthSecurityError("CSRF_TOKEN_MISSING", "The CSRF token is missing.");
1044
+ }
1045
+ ctx?.logger?.log("SIGN_OUT_ATTEMPT", {
1046
+ structuredData: {
1047
+ has_session: Boolean(session),
1048
+ has_csrf_token: Boolean(csrfToken),
1049
+ has_csrf_header: Boolean(header),
1050
+ skip_csrf_check: skipCSRFCheck
1051
+ }
1052
+ });
1053
+ if (!session) {
1054
+ ctx?.logger?.log("SESSION_TOKEN_MISSING");
1055
+ throw new AuthSecurityError("SESSION_TOKEN_MISSING", "The sessionToken is missing.");
1056
+ }
1057
+ if (!skipCSRFCheck) {
1058
+ if (!csrfToken) {
1059
+ ctx?.logger?.log("CSRF_TOKEN_MISSING");
1060
+ throw new AuthSecurityError("CSRF_TOKEN_MISSING", "The CSRF token is missing.");
1061
+ }
1062
+ if (!header) {
1063
+ ctx?.logger?.log("CSRF_HEADER_MISSING");
1064
+ throw new AuthSecurityError("CSRF_HEADER_MISSING", "The CSRF header is missing.");
1065
+ }
1066
+ try {
1067
+ await verifyCSRF(ctx.jose, csrfToken, header);
1068
+ } catch (error) {
1069
+ ctx?.logger?.log("CSRF_TOKEN_INVALID", { structuredData: { error_type: getErrorName(error) } });
1070
+ throw new AuthSecurityError("CSRF_TOKEN_INVALID", "CSRF token verification failed");
1071
+ }
1072
+ ctx?.logger?.log("SIGN_OUT_CSRF_VERIFIED");
1073
+ } else {
1074
+ try {
1075
+ await ctx.jose.verifyJWS(csrfToken);
1076
+ } catch (error) {
1077
+ ctx?.logger?.log("CSRF_TOKEN_INVALID", { structuredData: { error_type: getErrorName(error) } });
1078
+ throw new AuthSecurityError("CSRF_TOKEN_INVALID", "CSRF token verification failed");
1079
+ }
1080
+ }
1081
+ try {
1082
+ await ctx.jose.decodeJWT(session);
1083
+ ctx?.logger?.log("SIGN_OUT_SUCCESS");
1084
+ } catch (error) {
1085
+ ctx?.logger?.log("INVALID_JWT_TOKEN", { structuredData: { error_type: getErrorName(error) } });
1086
+ }
1087
+ const headersList = new import_router6.HeadersBuilder(secureApiHeaders).setHeader("Location", redirectTo).setCookie(ctx.cookies.csrfToken.name, "", expiredCookieAttributes).setCookie(ctx.cookies.sessionToken.name, "", expiredCookieAttributes).toHeaders();
1088
+ return Response.json(
1089
+ { redirect: Boolean(redirectTo), url: redirectTo },
1090
+ {
1091
+ status: 202,
1092
+ headers: headersList
1093
+ }
1094
+ );
1095
+ };
1096
+
1097
+ // src/actions/signOut/signOut.ts
1098
+ var config = (0, import_router7.createEndpointConfig)({
658
1099
  schemas: {
659
- searchParams: import_zod4.z.object({
660
- token_type_hint: import_zod4.z.literal("session_token"),
661
- redirectTo: import_zod4.z.string().optional()
1100
+ searchParams: import_v44.z.object({
1101
+ token_type_hint: import_v44.z.literal("session_token"),
1102
+ redirectTo: import_v44.z.string().optional()
662
1103
  })
663
1104
  }
664
1105
  });
665
- var signOutAction = (0, import_router5.createEndpoint)(
1106
+ var signOutAction = (0, import_router7.createEndpoint)(
666
1107
  "POST",
667
1108
  "/signOut",
668
1109
  async (ctx) => {
669
1110
  const {
670
1111
  request,
671
- headers,
672
1112
  searchParams: { redirectTo },
673
- context: { jose, cookies }
1113
+ context
674
1114
  } = ctx;
675
- const session = headers.getCookie(cookies.sessionToken.name);
676
- const csrfToken = headers.getCookie(cookies.csrfToken.name);
677
- const header = headers.getHeader("X-CSRF-Token");
678
- if (!session) {
679
- throw new AuthSecurityError("SESSION_TOKEN_MISSING", "The sessionToken is missing.");
680
- }
681
- if (!csrfToken) {
682
- throw new AuthSecurityError("CSRF_TOKEN_MISSING", "The CSRF token is missing.");
683
- }
684
- if (!header) {
685
- throw new AuthSecurityError("CSRF_TOKEN_MISSING", "The CSRF header is missing.");
686
- }
687
- await verifyCSRF(jose, csrfToken, header);
688
- await jose.decodeJWT(session);
689
- const normalizedOriginPath = getNormalizedOriginPath(request.url);
690
- const location = createRedirectTo(
691
- new Request(normalizedOriginPath, {
692
- headers: headers.toHeaders()
1115
+ const baseURL = getBaseURL(request);
1116
+ const location = await createRedirectTo(
1117
+ new Request(baseURL, {
1118
+ headers: request.headers
693
1119
  }),
694
- redirectTo
1120
+ redirectTo,
1121
+ context
695
1122
  );
696
- const headersList = new import_router5.HeadersBuilder(cacheControl).setHeader("Location", location).setCookie(cookies.csrfToken.name, "", expiredCookieAttributes).setCookie(cookies.sessionToken.name, "", expiredCookieAttributes).toHeaders();
697
- return Response.json({ message: "Signed out successfully" }, { status: import_router5.statusCode.ACCEPTED, headers: headersList });
1123
+ return await signOut({
1124
+ ctx: context,
1125
+ headers: request.headers,
1126
+ redirectTo: location
1127
+ });
698
1128
  },
699
1129
  config
700
1130
  );
701
1131
 
702
1132
  // src/actions/csrfToken/csrfToken.ts
703
- var import_router6 = require("@aura-stack/router");
1133
+ var import_router8 = require("@aura-stack/router");
704
1134
  var getCSRFToken = (request, cookieName) => {
705
1135
  try {
706
1136
  return getCookie(request, cookieName);
@@ -708,14 +1138,16 @@ var getCSRFToken = (request, cookieName) => {
708
1138
  return void 0;
709
1139
  }
710
1140
  };
711
- var csrfTokenAction = (0, import_router6.createEndpoint)("GET", "/csrfToken", async (ctx) => {
1141
+ var csrfTokenAction = (0, import_router8.createEndpoint)("GET", "/csrfToken", async (ctx) => {
712
1142
  const {
713
1143
  request,
714
- context: { jose, cookies }
1144
+ context: { jose, cookies, logger }
715
1145
  } = ctx;
716
1146
  const token = getCSRFToken(request, cookies.csrfToken.name);
1147
+ logger?.log("CSRF_TOKEN_REQUESTED", { structuredData: { has_token: Boolean(token) } });
717
1148
  const csrfToken = await createCSRF(jose, token);
718
- const headers = new Headers(cacheControl);
1149
+ logger?.log("CSRF_TOKEN_ISSUED", { structuredData: { issued: Boolean(csrfToken) } });
1150
+ const headers = new Headers(secureApiHeaders);
719
1151
  headers.append("Set-Cookie", setCookie(cookies.csrfToken.name, csrfToken, cookies.csrfToken.attributes));
720
1152
  return Response.json({ csrfToken }, { headers });
721
1153
  });