@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
@@ -0,0 +1,143 @@
1
+ import {
2
+ createAccessToken
3
+ } from "./chunk-TZB6MUXN.js";
4
+ import {
5
+ getUserInfo
6
+ } from "./chunk-XGLBNXL4.js";
7
+ import {
8
+ getOriginURL,
9
+ getTrustedOrigins
10
+ } from "./chunk-XUP6KKNG.js";
11
+ import {
12
+ OAuthAuthorizationErrorResponse
13
+ } from "./chunk-KJBAQZX2.js";
14
+ import {
15
+ createCSRF
16
+ } from "./chunk-NUDITUKX.js";
17
+ import {
18
+ isRelativeURL,
19
+ isSameOrigin,
20
+ isTrustedOrigin,
21
+ safeEquals
22
+ } from "./chunk-4EKY7655.js";
23
+ import {
24
+ createSessionCookie,
25
+ expiredCookieAttributes,
26
+ getCookie
27
+ } from "./chunk-5W4BRQYG.js";
28
+ import {
29
+ cacheControl
30
+ } from "./chunk-EBAMFRB7.js";
31
+ import {
32
+ AuthSecurityError,
33
+ OAuthProtocolError
34
+ } from "./chunk-RRLIF4PQ.js";
35
+
36
+ // src/actions/callback/callback.ts
37
+ import { z } from "zod";
38
+ import { createEndpoint, createEndpointConfig, HeadersBuilder } from "@aura-stack/router";
39
+ var callbackConfig = (oauth) => {
40
+ return createEndpointConfig("/callback/:oauth", {
41
+ schemas: {
42
+ params: z.object({
43
+ oauth: z.enum(
44
+ Object.keys(oauth),
45
+ "The OAuth provider is not supported or invalid."
46
+ )
47
+ }),
48
+ searchParams: z.object({
49
+ code: z.string("Missing code parameter in the OAuth authorization response."),
50
+ state: z.string("Missing state parameter in the OAuth authorization response.")
51
+ })
52
+ },
53
+ middlewares: [
54
+ (ctx) => {
55
+ const {
56
+ searchParams,
57
+ context: { logger }
58
+ } = ctx;
59
+ const response = OAuthAuthorizationErrorResponse.safeParse(searchParams);
60
+ if (response.success) {
61
+ const { error, error_description } = response.data;
62
+ const criticalAuthErrors = ["access_denied", "server_error"];
63
+ const severity = criticalAuthErrors.includes(error.toLowerCase()) ? "critical" : "warning";
64
+ logger?.log("OAUTH_AUTHORIZATION_ERROR", {
65
+ severity,
66
+ structuredData: {
67
+ error,
68
+ error_description: error_description ?? ""
69
+ }
70
+ });
71
+ throw new OAuthProtocolError(error, error_description || "OAuth Authorization Error");
72
+ }
73
+ return ctx;
74
+ }
75
+ ]
76
+ });
77
+ };
78
+ var callbackAction = (oauth) => {
79
+ return createEndpoint(
80
+ "GET",
81
+ "/callback/:oauth",
82
+ async (ctx) => {
83
+ const {
84
+ request,
85
+ params: { oauth: oauth2 },
86
+ searchParams: { code, state },
87
+ context
88
+ } = ctx;
89
+ const { oauth: providers, cookies, jose, logger, trustedOrigins } = context;
90
+ const oauthConfig = providers[oauth2];
91
+ const cookieState = getCookie(request, cookies.state.name);
92
+ const codeVerifier = getCookie(request, cookies.codeVerifier.name);
93
+ const cookieRedirectTo = getCookie(request, cookies.redirectTo.name);
94
+ const cookieRedirectURI = getCookie(request, cookies.redirectURI.name);
95
+ if (!safeEquals(cookieState, state)) {
96
+ logger?.log("MISMATCHING_STATE", {
97
+ structuredData: {
98
+ oauth_provider: oauth2
99
+ }
100
+ });
101
+ throw new AuthSecurityError(
102
+ "MISMATCHING_STATE",
103
+ "The provided state passed in the OAuth response does not match the stored state."
104
+ );
105
+ }
106
+ const accessToken = await createAccessToken(oauthConfig, cookieRedirectURI, code, codeVerifier, logger);
107
+ const origins = await getTrustedOrigins(request, trustedOrigins);
108
+ const requestOrigin = await getOriginURL(request, context);
109
+ if (!isRelativeURL(cookieRedirectTo)) {
110
+ const isValid = origins.length > 0 ? isTrustedOrigin(cookieRedirectTo, origins) : isSameOrigin(cookieRedirectTo, requestOrigin);
111
+ if (!isValid) {
112
+ logger?.log("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", {
113
+ structuredData: {
114
+ redirect_path: cookieRedirectTo,
115
+ provider: oauth2,
116
+ has_trusted_origins: origins.length > 0,
117
+ request_origin: requestOrigin
118
+ }
119
+ });
120
+ throw new AuthSecurityError(
121
+ "POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
122
+ "Invalid redirect path. Potential open redirect attack detected."
123
+ );
124
+ }
125
+ }
126
+ const userInfo = await getUserInfo(oauthConfig, accessToken.access_token, logger);
127
+ const sessionCookie = await createSessionCookie(jose, userInfo);
128
+ const csrfToken = await createCSRF(jose);
129
+ logger?.log("OAUTH_CALLBACK_SUCCESS", {
130
+ structuredData: {
131
+ provider: oauth2
132
+ }
133
+ });
134
+ const headers = new 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();
135
+ return Response.json({ oauth: oauth2 }, { status: 302, headers });
136
+ },
137
+ callbackConfig(oauth)
138
+ );
139
+ };
140
+
141
+ export {
142
+ callbackAction
143
+ };
@@ -2,14 +2,14 @@ import {
2
2
  createAuthorizationURL,
3
3
  createRedirectTo,
4
4
  createRedirectURI
5
- } from "./chunk-N4SX7TZT.js";
6
- import {
7
- cacheControl
8
- } from "./chunk-STHEPPUZ.js";
5
+ } from "./chunk-XUP6KKNG.js";
9
6
  import {
10
7
  createPKCE,
11
8
  generateSecure
12
- } from "./chunk-N2APGLXA.js";
9
+ } from "./chunk-NUDITUKX.js";
10
+ import {
11
+ cacheControl
12
+ } from "./chunk-EBAMFRB7.js";
13
13
 
14
14
  // src/actions/signIn/signIn.ts
15
15
  import { z } from "zod";
@@ -38,13 +38,17 @@ var signInAction = (oauth) => {
38
38
  request,
39
39
  params: { oauth: oauth2 },
40
40
  searchParams: { redirectTo },
41
- context: { oauth: providers, cookies, trustedProxyHeaders, basePath }
41
+ context
42
42
  } = ctx;
43
+ const { oauth: providers, cookies, logger } = context;
43
44
  const state = generateSecure();
44
- const redirectURI = createRedirectURI(request, oauth2, basePath, trustedProxyHeaders);
45
- const redirectToValue = createRedirectTo(request, redirectTo, trustedProxyHeaders);
45
+ const redirectURI = await createRedirectURI(request, oauth2, context);
46
+ const redirectToValue = await createRedirectTo(request, redirectTo, context);
46
47
  const { codeVerifier, codeChallenge, method } = await createPKCE();
47
- const authorization = createAuthorizationURL(providers[oauth2], redirectURI, state, codeChallenge, method);
48
+ const authorization = createAuthorizationURL(providers[oauth2], redirectURI, state, codeChallenge, method, logger);
49
+ logger?.log("SIGN_IN_INITIATED", {
50
+ structuredData: { oauth_provider: oauth2, code_challenge_method: method }
51
+ });
48
52
  const headers = new 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();
49
53
  return Response.json(
50
54
  { oauth: oauth2 },
@@ -0,0 +1,95 @@
1
+ import {
2
+ createRedirectTo
3
+ } from "./chunk-XUP6KKNG.js";
4
+ import {
5
+ verifyCSRF
6
+ } from "./chunk-NUDITUKX.js";
7
+ import {
8
+ getBaseURL,
9
+ getErrorName
10
+ } from "./chunk-QQVSRXGX.js";
11
+ import {
12
+ expiredCookieAttributes
13
+ } from "./chunk-5W4BRQYG.js";
14
+ import {
15
+ secureApiHeaders
16
+ } from "./chunk-EBAMFRB7.js";
17
+ import {
18
+ AuthSecurityError
19
+ } from "./chunk-RRLIF4PQ.js";
20
+
21
+ // src/actions/signOut/signOut.ts
22
+ import { z } from "zod";
23
+ import { createEndpoint, createEndpointConfig, HeadersBuilder, statusCode } from "@aura-stack/router";
24
+ var config = createEndpointConfig({
25
+ schemas: {
26
+ searchParams: z.object({
27
+ token_type_hint: z.literal("session_token"),
28
+ redirectTo: z.string().optional()
29
+ })
30
+ }
31
+ });
32
+ var signOutAction = createEndpoint(
33
+ "POST",
34
+ "/signOut",
35
+ async (ctx) => {
36
+ const {
37
+ request,
38
+ headers,
39
+ searchParams: { redirectTo },
40
+ context
41
+ } = ctx;
42
+ const { jose, cookies, logger } = context;
43
+ const session = headers.getCookie(cookies.sessionToken.name);
44
+ const csrfToken = headers.getCookie(cookies.csrfToken.name);
45
+ const header = headers.getHeader("X-CSRF-Token");
46
+ logger?.log("SIGN_OUT_ATTEMPT", {
47
+ structuredData: {
48
+ has_session: Boolean(session),
49
+ has_csrf_token: Boolean(csrfToken),
50
+ has_csrf_header: Boolean(header)
51
+ }
52
+ });
53
+ if (!session) {
54
+ logger?.log("SESSION_TOKEN_MISSING");
55
+ throw new AuthSecurityError("SESSION_TOKEN_MISSING", "The sessionToken is missing.");
56
+ }
57
+ if (!csrfToken) {
58
+ logger?.log("CSRF_TOKEN_MISSING");
59
+ throw new AuthSecurityError("CSRF_TOKEN_MISSING", "The CSRF token is missing.");
60
+ }
61
+ if (!header) {
62
+ logger?.log("CSRF_HEADER_MISSING");
63
+ throw new AuthSecurityError("CSRF_HEADER_MISSING", "The CSRF header is missing.");
64
+ }
65
+ try {
66
+ await verifyCSRF(jose, csrfToken, header);
67
+ } catch (error) {
68
+ logger?.log("CSRF_TOKEN_INVALID", { structuredData: { error_type: getErrorName(error) } });
69
+ throw new AuthSecurityError("CSRF_TOKEN_INVALID", "CSRF token verification failed");
70
+ }
71
+ logger?.log("SIGN_OUT_CSRF_VERIFIED");
72
+ try {
73
+ await jose.decodeJWT(session);
74
+ logger?.log("SIGN_OUT_SUCCESS");
75
+ } catch (error) {
76
+ logger?.log("INVALID_JWT_TOKEN", { structuredData: { error_type: getErrorName(error) } });
77
+ }
78
+ const baseURL = getBaseURL(request);
79
+ const location = await createRedirectTo(
80
+ new Request(baseURL, {
81
+ headers: headers.toHeaders()
82
+ }),
83
+ redirectTo,
84
+ context
85
+ );
86
+ logger?.log("SIGN_OUT_REDIRECT", { structuredData: { location } });
87
+ const headersList = new HeadersBuilder(secureApiHeaders).setHeader("Location", location).setCookie(cookies.csrfToken.name, "", expiredCookieAttributes).setCookie(cookies.sessionToken.name, "", expiredCookieAttributes).toHeaders();
88
+ return Response.json({ message: "Signed out successfully" }, { status: statusCode.ACCEPTED, headers: headersList });
89
+ },
90
+ config
91
+ );
92
+
93
+ export {
94
+ signOutAction
95
+ };
@@ -0,0 +1,25 @@
1
+ // src/oauth/pinterest.ts
2
+ var pinterest = (options) => {
3
+ return {
4
+ id: "pinterest",
5
+ name: "Pinterest",
6
+ authorizeURL: "https://www.pinterest.com/oauth",
7
+ accessToken: "https://api.pinterest.com/v5/oauth/token",
8
+ userInfo: "https://api.pinterest.com/v5/user_account",
9
+ scope: "user_accounts:read",
10
+ responseType: "code",
11
+ profile(profile) {
12
+ return {
13
+ sub: profile.id,
14
+ name: profile.username,
15
+ image: profile.profile_image,
16
+ email: void 0
17
+ };
18
+ },
19
+ ...options
20
+ };
21
+ };
22
+
23
+ export {
24
+ pinterest
25
+ };
@@ -0,0 +1,34 @@
1
+ // src/headers.ts
2
+ var cacheControl = {
3
+ "Cache-Control": "no-store",
4
+ Pragma: "no-cache",
5
+ Expires: "0",
6
+ Vary: "Cookie"
7
+ };
8
+ var contentSecurityPolicy = {
9
+ "Content-Security-Policy": [
10
+ "default-src 'none'",
11
+ "script-src 'self'",
12
+ "frame-src 'none'",
13
+ "object-src 'none'",
14
+ "frame-ancestors 'none'",
15
+ "base-uri 'none'"
16
+ ].join("; ")
17
+ };
18
+ var secureHeaders = {
19
+ "X-Content-Type-Options": "nosniff",
20
+ "X-Frame-Options": "DENY",
21
+ "Referrer-Policy": "strict-origin-when-cross-origin"
22
+ };
23
+ var secureApiHeaders = {
24
+ ...cacheControl,
25
+ ...contentSecurityPolicy,
26
+ ...secureHeaders
27
+ };
28
+
29
+ export {
30
+ cacheControl,
31
+ contentSecurityPolicy,
32
+ secureHeaders,
33
+ secureApiHeaders
34
+ };
@@ -0,0 +1,25 @@
1
+ // src/oauth/x.ts
2
+ var x = (options) => {
3
+ return {
4
+ id: "x",
5
+ name: "X",
6
+ authorizeURL: "https://twitter.com/i/oauth2/authorize",
7
+ accessToken: "https://api.twitter.com/2/oauth2/token",
8
+ userInfo: "https://api.twitter.com/2/users/me?user.fields=profile_image_url",
9
+ scope: "tweet.read users.read offline.access",
10
+ responseType: "code",
11
+ profile(profile) {
12
+ return {
13
+ sub: profile.data.id,
14
+ name: profile.data.name,
15
+ image: profile.data.profile_image_url,
16
+ email: void 0
17
+ };
18
+ },
19
+ ...options
20
+ };
21
+ };
22
+
23
+ export {
24
+ x
25
+ };
@@ -1,15 +1,19 @@
1
1
  import {
2
- createDerivedSalt
3
- } from "./chunk-N2APGLXA.js";
2
+ env
3
+ } from "./chunk-4MYWAOLG.js";
4
4
  import {
5
5
  AuthInternalError
6
6
  } from "./chunk-RRLIF4PQ.js";
7
7
 
8
8
  // src/jose.ts
9
- import "dotenv/config";
10
- import { createJWT, createJWS, createJWE, createDeriveKey } from "@aura-stack/jose";
9
+ import {
10
+ createJWT,
11
+ createJWS,
12
+ createJWE,
13
+ createDeriveKey,
14
+ createSecret
15
+ } from "@aura-stack/jose";
11
16
  var createJoseInstance = (secret) => {
12
- const env = process.env;
13
17
  secret ??= env.AURA_AUTH_SECRET ?? env.AUTH_SECRET;
14
18
  if (!secret) {
15
19
  throw new AuthInternalError(
@@ -17,7 +21,22 @@ var createJoseInstance = (secret) => {
17
21
  "AURA_AUTH_SECRET environment variable is not set and no secret was provided."
18
22
  );
19
23
  }
20
- const salt = env.AURA_AUTH_SALT ?? env.AUTH_SALT ?? createDerivedSalt(secret);
24
+ const salt = env.AURA_AUTH_SALT ?? env.AUTH_SALT;
25
+ if (!salt) {
26
+ throw new AuthInternalError(
27
+ "JOSE_INITIALIZATION_FAILED",
28
+ "AURA_AUTH_SALT or AUTH_SALT environment variable is not set. A salt value is required for key derivation."
29
+ );
30
+ }
31
+ try {
32
+ createSecret(salt);
33
+ } catch (error) {
34
+ throw new AuthInternalError(
35
+ "INVALID_SALT_SECRET_VALUE",
36
+ "AURA_AUTH_SALT/AUTH_SALT is invalid. It must be at least 32 bytes long and meet entropy requirements.",
37
+ { cause: error }
38
+ );
39
+ }
21
40
  const { derivedKey: derivedSigningKey } = createDeriveKey(secret, salt, "signing");
22
41
  const { derivedKey: derivedEncryptionKey } = createDeriveKey(secret, salt, "encryption");
23
42
  const { derivedKey: derivedCsrfTokenKey } = createDeriveKey(secret, salt, "csrfToken");
@@ -33,7 +52,19 @@ var createJoseInstance = (secret) => {
33
52
  decryptJWE
34
53
  };
35
54
  };
55
+ var jwtVerificationOptions = {
56
+ algorithms: ["HS256"],
57
+ typ: "JWT"
58
+ };
59
+ var decodeJWTOptions = {
60
+ jws: jwtVerificationOptions,
61
+ jwt: {
62
+ typ: "JWT"
63
+ }
64
+ };
36
65
 
37
66
  export {
38
- createJoseInstance
67
+ createJoseInstance,
68
+ jwtVerificationOptions,
69
+ decodeJWTOptions
39
70
  };
@@ -0,0 +1,25 @@
1
+ // src/oauth/github.ts
2
+ var github = (options) => {
3
+ return {
4
+ id: "github",
5
+ name: "GitHub",
6
+ authorizeURL: "https://github.com/login/oauth/authorize",
7
+ accessToken: "https://github.com/login/oauth/access_token",
8
+ userInfo: "https://api.github.com/user",
9
+ scope: "read:user user:email",
10
+ responseType: "code",
11
+ profile: (profile) => {
12
+ return {
13
+ sub: profile.id.toString(),
14
+ name: profile.name ?? profile.login,
15
+ email: profile.email ?? void 0,
16
+ image: profile.avatar_url
17
+ };
18
+ },
19
+ ...options
20
+ };
21
+ };
22
+
23
+ export {
24
+ github
25
+ };
@@ -1,13 +1,13 @@
1
+ import {
2
+ createCSRF
3
+ } from "./chunk-NUDITUKX.js";
1
4
  import {
2
5
  getCookie,
3
6
  setCookie
4
- } from "./chunk-W6LG7BFW.js";
7
+ } from "./chunk-5W4BRQYG.js";
5
8
  import {
6
- cacheControl
7
- } from "./chunk-STHEPPUZ.js";
8
- import {
9
- createCSRF
10
- } from "./chunk-N2APGLXA.js";
9
+ secureApiHeaders
10
+ } from "./chunk-EBAMFRB7.js";
11
11
 
12
12
  // src/actions/csrfToken/csrfToken.ts
13
13
  import { createEndpoint } from "@aura-stack/router";
@@ -21,11 +21,13 @@ var getCSRFToken = (request, cookieName) => {
21
21
  var csrfTokenAction = createEndpoint("GET", "/csrfToken", async (ctx) => {
22
22
  const {
23
23
  request,
24
- context: { jose, cookies }
24
+ context: { jose, cookies, logger }
25
25
  } = ctx;
26
26
  const token = getCSRFToken(request, cookies.csrfToken.name);
27
+ logger?.log("CSRF_TOKEN_REQUESTED", { structuredData: { has_token: Boolean(token) } });
27
28
  const csrfToken = await createCSRF(jose, token);
28
- const headers = new Headers(cacheControl);
29
+ logger?.log("CSRF_TOKEN_ISSUED", { structuredData: { issued: Boolean(csrfToken) } });
30
+ const headers = new Headers(secureApiHeaders);
29
31
  headers.append("Set-Cookie", setCookie(cookies.csrfToken.name, csrfToken, cookies.csrfToken.attributes));
30
32
  return Response.json({ csrfToken }, { headers });
31
33
  });
@@ -0,0 +1,25 @@
1
+ // src/oauth/spotify.ts
2
+ var spotify = (options) => {
3
+ return {
4
+ id: "spotify",
5
+ name: "Spotify",
6
+ authorizeURL: "https://accounts.spotify.com/authorize",
7
+ accessToken: "https://accounts.spotify.com/api/token",
8
+ userInfo: "https://api.spotify.com/v1/me",
9
+ scope: "user-read-private user-read-email",
10
+ responseType: "code",
11
+ profile(profile) {
12
+ return {
13
+ sub: profile.id,
14
+ name: profile.display_name,
15
+ email: profile.email,
16
+ image: profile.images[0]?.url ?? void 0
17
+ };
18
+ },
19
+ ...options
20
+ };
21
+ };
22
+
23
+ export {
24
+ spotify
25
+ };
@@ -1,5 +1,17 @@
1
1
  // src/schemas.ts
2
2
  import { object, string, enum as options, number, z, null as nullable } from "zod";
3
+ var OAuthProviderCredentialsSchema = object({
4
+ id: string(),
5
+ name: string(),
6
+ authorizeURL: string().url(),
7
+ accessToken: string().url(),
8
+ scope: string(),
9
+ userInfo: string().url(),
10
+ responseType: options(["code", "token", "id_token"]),
11
+ clientId: string(),
12
+ clientSecret: string(),
13
+ profile: z.function().optional()
14
+ });
3
15
  var OAuthProviderConfigSchema = object({
4
16
  authorizeURL: string().url(),
5
17
  accessToken: string().url(),
@@ -67,6 +79,7 @@ var OAuthEnvSchema = object({
67
79
  });
68
80
 
69
81
  export {
82
+ OAuthProviderCredentialsSchema,
70
83
  OAuthProviderConfigSchema,
71
84
  OAuthAuthorization,
72
85
  OAuthAuthorizationResponse,
@@ -0,0 +1,25 @@
1
+ // src/oauth/figma.ts
2
+ var figma = (options) => {
3
+ return {
4
+ id: "figma",
5
+ name: "Figma",
6
+ authorizeURL: "https://www.figma.com/oauth",
7
+ accessToken: "https://api.figma.com/v1/oauth/token",
8
+ userInfo: "https://api.figma.com/v1/me",
9
+ scope: "current_user:read",
10
+ responseType: "code",
11
+ profile(profile) {
12
+ return {
13
+ sub: profile.id,
14
+ name: profile.handle,
15
+ email: profile.email,
16
+ image: profile.img_url
17
+ };
18
+ },
19
+ ...options
20
+ };
21
+ };
22
+
23
+ export {
24
+ figma
25
+ };
@@ -0,0 +1,25 @@
1
+ // src/oauth/mailchimp.ts
2
+ var mailchimp = (options) => {
3
+ return {
4
+ id: "mailchimp",
5
+ name: "Mailchimp",
6
+ authorizeURL: "https://login.mailchimp.com/oauth2/authorize",
7
+ accessToken: "https://login.mailchimp.com/oauth2/token",
8
+ userInfo: "https://login.mailchimp.com/oauth2/metadata",
9
+ scope: "",
10
+ responseType: "code",
11
+ profile(profile) {
12
+ return {
13
+ sub: profile.user_id,
14
+ name: profile.accountname,
15
+ email: profile.login.email,
16
+ image: profile.login.avatar
17
+ };
18
+ },
19
+ ...options
20
+ };
21
+ };
22
+
23
+ export {
24
+ mailchimp
25
+ };
@@ -1,9 +1,13 @@
1
+ import {
2
+ isJWTPayloadWithToken,
3
+ safeEquals
4
+ } from "./chunk-4EKY7655.js";
1
5
  import {
2
6
  equals
3
- } from "./chunk-CXLATHS5.js";
7
+ } from "./chunk-QQVSRXGX.js";
4
8
  import {
5
- isJWTPayloadWithToken
6
- } from "./chunk-EIL2FPSS.js";
9
+ jwtVerificationOptions
10
+ } from "./chunk-FRJFWTOY.js";
7
11
  import {
8
12
  AuthSecurityError
9
13
  } from "./chunk-RRLIF4PQ.js";
@@ -17,7 +21,11 @@ var createHash = (data, base = "hex") => {
17
21
  return crypto.createHash("sha256").update(data).digest().toString(base);
18
22
  };
19
23
  var createPKCE = async (verifier) => {
20
- const codeVerifier = verifier ?? generateSecure(86);
24
+ const byteLength = verifier ? void 0 : Math.floor(Math.random() * (96 - 32 + 1) + 32);
25
+ const codeVerifier = verifier ?? generateSecure(byteLength ?? 64);
26
+ if (codeVerifier.length < 43 || codeVerifier.length > 128) {
27
+ throw new AuthSecurityError("PKCE_VERIFIER_INVALID", "The code verifier must be between 43 and 128 characters in length.");
28
+ }
21
29
  const codeChallenge = createHash(codeVerifier, "base64url");
22
30
  return { codeVerifier, codeChallenge, method: "S256" };
23
31
  };
@@ -25,7 +33,7 @@ var createCSRF = async (jose, csrfCookie) => {
25
33
  try {
26
34
  const token = generateSecure(32);
27
35
  if (csrfCookie) {
28
- await jose.verifyJWS(csrfCookie);
36
+ await jose.verifyJWS(csrfCookie, jwtVerificationOptions);
29
37
  return csrfCookie;
30
38
  }
31
39
  return jose.signJWS({ token });
@@ -36,20 +44,18 @@ var createCSRF = async (jose, csrfCookie) => {
36
44
  };
37
45
  var verifyCSRF = async (jose, cookie, header) => {
38
46
  try {
39
- const cookiePayload = await jose.verifyJWS(cookie);
40
- const headerPayload = await jose.verifyJWS(header);
47
+ const cookiePayload = await jose.verifyJWS(cookie, jwtVerificationOptions);
48
+ const headerPayload = await jose.verifyJWS(header, jwtVerificationOptions);
41
49
  if (!isJWTPayloadWithToken(cookiePayload)) {
42
50
  throw new AuthSecurityError("CSRF_TOKEN_INVALID", "Cookie payload missing token field.");
43
51
  }
44
52
  if (!isJWTPayloadWithToken(headerPayload)) {
45
53
  throw new AuthSecurityError("CSRF_TOKEN_INVALID", "Header payload missing token field.");
46
54
  }
47
- const cookieBuffer = Buffer.from(cookiePayload.token);
48
- const headerBuffer = Buffer.from(headerPayload.token);
49
- if (!equals(headerBuffer.length, cookieBuffer.length)) {
55
+ if (!equals(cookiePayload.token.length, headerPayload.token.length)) {
50
56
  throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
51
57
  }
52
- if (!crypto.timingSafeEqual(cookieBuffer, headerBuffer)) {
58
+ if (!safeEquals(cookiePayload.token, headerPayload.token)) {
53
59
  throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
54
60
  }
55
61
  return true;
@@ -57,15 +63,11 @@ var verifyCSRF = async (jose, cookie, header) => {
57
63
  throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
58
64
  }
59
65
  };
60
- var createDerivedSalt = (secret) => {
61
- return crypto.createHash("sha256").update(secret).update("aura-auth-salt").digest("hex");
62
- };
63
66
 
64
67
  export {
65
68
  generateSecure,
66
69
  createHash,
67
70
  createPKCE,
68
71
  createCSRF,
69
- verifyCSRF,
70
- createDerivedSalt
72
+ verifyCSRF
71
73
  };