@neondatabase/auth 0.2.0-beta.1 → 0.3.0-beta

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 (37) hide show
  1. package/LICENSE +201 -0
  2. package/dist/{adapter-core-CnrOXh1T.d.mts → adapter-core-B9uDhoYq.d.mts} +291 -362
  3. package/dist/{adapter-core-CtmnMMJ7.mjs → adapter-core-D00qcqMo.mjs} +1 -1
  4. package/dist/{better-auth-react-adapter-DNi5PC5D.d.mts → better-auth-react-adapter-BO4jLN4H.d.mts} +251 -251
  5. package/dist/{better-auth-react-adapter-Dv-o6A6O.mjs → better-auth-react-adapter-Xdj-69i9.mjs} +1 -1
  6. package/dist/{index-CzsGMS7C.d.mts → index-B_Q0Tp1D.d.mts} +0 -1
  7. package/dist/index.d.mts +92 -4
  8. package/dist/index.mjs +2 -2
  9. package/dist/{neon-auth-Cs2cWh1B.mjs → neon-auth-DBOB8sXF.mjs} +1 -1
  10. package/dist/next/index.d.mts +17 -17
  11. package/dist/next/index.mjs +3 -3
  12. package/dist/next/server/index.d.mts +2 -4
  13. package/dist/next/server/index.mjs +323 -235
  14. package/dist/react/adapters/index.d.mts +3 -3
  15. package/dist/react/adapters/index.mjs +2 -2
  16. package/dist/react/index.d.mts +6 -5
  17. package/dist/react/index.mjs +5 -5
  18. package/dist/react/ui/index.d.mts +1 -2
  19. package/dist/react/ui/index.mjs +2 -4
  20. package/dist/react/ui/server.mjs +2 -2
  21. package/dist/{supabase-adapter-BlcGPyOf.mjs → supabase-adapter-CIBMebXB.mjs} +1 -1
  22. package/dist/{supabase-adapter-DUqw2fw8.d.mts → supabase-adapter-CSDRL1ZU.d.mts} +285 -316
  23. package/dist/types/index.d.mts +2 -2
  24. package/dist/ui/.safelist.html +1 -1
  25. package/dist/ui/css.css +2 -2
  26. package/dist/ui/theme.css +1 -1
  27. package/dist/ui-CnVnqGns.mjs +3 -0
  28. package/dist/vanilla/adapters/index.d.mts +3 -3
  29. package/dist/vanilla/adapters/index.mjs +2 -2
  30. package/dist/vanilla/index.d.mts +3 -3
  31. package/dist/vanilla/index.mjs +2 -2
  32. package/package.json +23 -21
  33. package/dist/chunk-VCZJYX65-CLnrj1o7-D6ZQkcc_.mjs +0 -543
  34. package/dist/neon-auth-BEGCfAe6.d.mts +0 -107
  35. package/dist/ui-COLWzDsu.mjs +0 -12469
  36. /package/dist/{adapters-B7YKkjaL.mjs → adapters-CUvhsAvY.mjs} +0 -0
  37. /package/dist/{index-OEBbnNdr.d.mts → index-UW23fDSn.d.mts} +0 -0
@@ -473,6 +473,35 @@ async function getSessionDataFromCookie(request, cookieName, cookieSecret) {
473
473
  return null;
474
474
  }
475
475
  }
476
+ /**
477
+ * Fetch session data from upstream using session token cookie
478
+ *
479
+ * @param sessionTokenCookie - Session token cookie string (can be Set-Cookie header or "name=value" format)
480
+ * @param baseUrl - Auth server base URL
481
+ * @returns Session data from upstream
482
+ */
483
+ async function fetchSessionWithCookie(sessionTokenCookie, baseUrl) {
484
+ let cookieName;
485
+ let cookieValue;
486
+ if (sessionTokenCookie.includes("=")) {
487
+ const [name, ...valueParts] = sessionTokenCookie.split(";")[0].trim().split("=");
488
+ cookieName = name.trim();
489
+ cookieValue = valueParts.join("=").trim();
490
+ } else throw new Error("Invalid session token cookie format");
491
+ if (!cookieName.includes("session_token")) throw new Error("session_token not found in cookie");
492
+ const response = await fetch(`${baseUrl}/get-session`, {
493
+ headers: { Cookie: `${cookieName}=${cookieValue}` },
494
+ signal: AbortSignal.timeout(3e3)
495
+ });
496
+ if (!response.ok) throw new Error(`Failed to fetch session data: ${response.status} ${response.statusText}`);
497
+ let body;
498
+ try {
499
+ body = await response.json();
500
+ } catch (error) {
501
+ throw new Error(`Failed to parse /get-session response as JSON: ${error instanceof Error ? error.message : String(error)}`);
502
+ }
503
+ return parseSessionData(body);
504
+ }
476
505
 
477
506
  //#endregion
478
507
  //#region src/server/errors.ts
@@ -506,6 +535,241 @@ async function validateSessionData(sessionDataString, cookieSecret) {
506
535
  }
507
536
  }
508
537
 
538
+ //#endregion
539
+ //#region src/server/session/minting.ts
540
+ /**
541
+ * Core minting logic - creates session_data cookie from session token
542
+ *
543
+ * @param sessionTokenCookie - Session token cookie string (format: "name=value")
544
+ * @param baseUrl - Auth server base URL
545
+ * @param cookieConfig - Cookie configuration
546
+ * @returns Set-Cookie string or null on error
547
+ */
548
+ async function mintSessionDataCookie(sessionTokenCookie, baseUrl, cookieConfig) {
549
+ try {
550
+ const sessionData = await fetchSessionWithCookie(sessionTokenCookie, baseUrl);
551
+ if (!sessionData.session) return null;
552
+ const { value: signedData, expiresAt } = await signSessionDataCookie(sessionData, cookieConfig.secret, cookieConfig.sessionDataTtl);
553
+ const maxAge = Math.floor((expiresAt.getTime() - Date.now()) / 1e3);
554
+ return serializeSetCookie({
555
+ name: NEON_AUTH_SESSION_DATA_COOKIE_NAME,
556
+ value: signedData,
557
+ path: "/",
558
+ domain: cookieConfig.domain,
559
+ httpOnly: true,
560
+ secure: true,
561
+ sameSite: "lax",
562
+ maxAge
563
+ });
564
+ } catch (error) {
565
+ const errorMessage = error instanceof Error ? error.message : String(error);
566
+ console.error("[mintSessionDataCookie] Failed to mint session_data cookie:", {
567
+ error: errorMessage,
568
+ ...process.env.NODE_ENV !== "production" && { stack: error instanceof Error ? error.stack : void 0 }
569
+ });
570
+ return null;
571
+ }
572
+ }
573
+ /**
574
+ * Utility A: Mint session_data cookie when session_token is updated by upstream
575
+ *
576
+ * Checks response headers for session_token in Set-Cookie, then mints session_data.
577
+ * Handles token deletion (max-age=0) by returning deletion cookie.
578
+ *
579
+ * Use case: Response handling in proxy/middleware after upstream auth calls
580
+ *
581
+ * @param responseHeaders - Response headers from upstream auth server
582
+ * @param baseUrl - Auth server base URL
583
+ * @param cookieConfig - Cookie configuration
584
+ * @returns Set-Cookie string for session_data or null if no action needed
585
+ */
586
+ async function mintSessionDataFromResponse(responseHeaders, baseUrl, cookieConfig) {
587
+ const sessionTokenCookie = responseHeaders.getSetCookie().find((cookie) => cookie.includes("session_token"));
588
+ if (!sessionTokenCookie) return null;
589
+ if (sessionTokenCookie.toLowerCase().includes("max-age=0")) return serializeSetCookie({
590
+ name: NEON_AUTH_SESSION_DATA_COOKIE_NAME,
591
+ value: "",
592
+ path: "/",
593
+ domain: cookieConfig.domain,
594
+ httpOnly: true,
595
+ secure: true,
596
+ sameSite: "lax",
597
+ maxAge: 0
598
+ });
599
+ return await mintSessionDataCookie(sessionTokenCookie, baseUrl, cookieConfig);
600
+ }
601
+ /**
602
+ * Utility B: Mint/refresh session_data cookie from existing session_token
603
+ *
604
+ * Extracts session_token from request cookies and mints a fresh session_data cookie.
605
+ * Use case: Cache misses, expired cookies, proactive refresh
606
+ *
607
+ * @param sessionTokenCookie - Session token cookie string (format: "name=value")
608
+ * @param baseUrl - Auth server base URL
609
+ * @param cookieConfig - Cookie configuration
610
+ * @returns Set-Cookie string for session_data or null on error
611
+ */
612
+ async function mintSessionDataFromToken(sessionTokenCookie, baseUrl, cookieConfig) {
613
+ return await mintSessionDataCookie(sessionTokenCookie, baseUrl, cookieConfig);
614
+ }
615
+
616
+ //#endregion
617
+ //#region src/server/client-factory.ts
618
+ function createAuthServerInternal(config) {
619
+ const { baseUrl, context: getContext, cookieSecret, sessionDataTtl, domain } = config;
620
+ const fetchWithAuth = async (path, method, args) => {
621
+ const ctx = await getContext();
622
+ const cookies$1 = await ctx.getCookies();
623
+ const origin = await ctx.getOrigin();
624
+ const framework = ctx.getFramework();
625
+ const url = new URL(path, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`);
626
+ const { query, fetchOptions: _fetchOptions, ...body } = args || {};
627
+ if (query && typeof query === "object") {
628
+ const queryParams = query;
629
+ for (const [key, value] of Object.entries(queryParams)) if (value !== void 0 && value !== null) url.searchParams.set(key, String(value));
630
+ }
631
+ const headers$1 = {
632
+ Cookie: cookies$1,
633
+ Origin: origin,
634
+ [NEON_AUTH_SERVER_PROXY_HEADER]: framework
635
+ };
636
+ let requestBody;
637
+ if (method === "POST") {
638
+ headers$1["Content-Type"] = "application/json";
639
+ requestBody = JSON.stringify(Object.keys(body).length > 0 ? body : {});
640
+ }
641
+ const response = await fetch(url.toString(), {
642
+ method,
643
+ headers: headers$1,
644
+ body: requestBody
645
+ });
646
+ const setCookieHeaders = response.headers.getSetCookie();
647
+ if (setCookieHeaders.length > 0) {
648
+ for (const setCookieHeader of setCookieHeaders) {
649
+ const parsedCookies = parseSetCookies(setCookieHeader);
650
+ for (const cookie of parsedCookies) {
651
+ const cookieOptions = {
652
+ ...cookie,
653
+ domain,
654
+ partitioned: void 0,
655
+ sameSite: "lax"
656
+ };
657
+ await ctx.setCookie(cookie.name, cookie.value, cookieOptions);
658
+ }
659
+ }
660
+ try {
661
+ const sessionDataCookie = await mintSessionDataFromResponse(response.headers, baseUrl, {
662
+ secret: cookieSecret,
663
+ sessionDataTtl,
664
+ domain
665
+ });
666
+ if (sessionDataCookie) {
667
+ const [parsedSessionData] = parseSetCookies(sessionDataCookie);
668
+ if (parsedSessionData) await ctx.setCookie(parsedSessionData.name, parsedSessionData.value, parsedSessionData);
669
+ }
670
+ } catch (error) {
671
+ console.error("[fetchWithAuth] Failed to mint session data cookie:", error);
672
+ }
673
+ }
674
+ const responseData = await response.json().catch(() => null);
675
+ if (!response.ok) return {
676
+ data: null,
677
+ error: {
678
+ message: responseData?.message || response.statusText,
679
+ status: response.status,
680
+ statusText: response.statusText
681
+ }
682
+ };
683
+ return {
684
+ data: responseData,
685
+ error: null
686
+ };
687
+ };
688
+ const baseServer = createApiProxy(API_ENDPOINTS, fetchWithAuth);
689
+ const originalGetSession = baseServer.getSession;
690
+ baseServer.getSession = async (...args) => {
691
+ const [data] = args;
692
+ if (!(data?.query?.disableCookieCache === "true")) try {
693
+ const cookiesString = await (await getContext()).getCookies();
694
+ const hasSessionToken = cookiesString.includes(NEON_AUTH_SESSION_COOKIE_NAME);
695
+ const sessionDataCookie = parseCookieValue(cookiesString, NEON_AUTH_SESSION_DATA_COOKIE_NAME);
696
+ if (sessionDataCookie && hasSessionToken) {
697
+ const result = await validateSessionData(sessionDataCookie, cookieSecret);
698
+ if (result.valid && result.payload) return {
699
+ data: result.payload,
700
+ error: null
701
+ };
702
+ }
703
+ } catch (error) {
704
+ console.error("[auth.getSession] Cookie validation error:", error);
705
+ }
706
+ return originalGetSession(...args);
707
+ };
708
+ return baseServer;
709
+ }
710
+ function isEndpointConfig(value) {
711
+ return typeof value === "object" && value !== null && "path" in value && "method" in value;
712
+ }
713
+ function createApiProxy(endpoints, fetchFn) {
714
+ return new Proxy({}, {
715
+ get(target, prop) {
716
+ if (prop in target) return target[prop];
717
+ const endpoint = endpoints[prop];
718
+ if (!endpoint) return;
719
+ if (isEndpointConfig(endpoint)) return (args) => fetchFn(endpoint.path, endpoint.method, args);
720
+ return createApiProxy(endpoint, fetchFn);
721
+ },
722
+ set(target, prop, value) {
723
+ target[prop] = value;
724
+ return true;
725
+ }
726
+ });
727
+ }
728
+
729
+ //#endregion
730
+ //#region src/next/server/adapter.ts
731
+ /**
732
+ * Creates a Next.js-specific RequestContext that reads cookies and headers
733
+ * from next/headers and handles cookie setting.
734
+ */
735
+ async function createNextRequestContext() {
736
+ const cookieStore = await cookies();
737
+ const headerStore = await headers();
738
+ return {
739
+ getCookies() {
740
+ return extractNeonAuthCookies(headerStore);
741
+ },
742
+ setCookie(name, value, options) {
743
+ cookieStore.set(name, value, options);
744
+ },
745
+ getHeader(name) {
746
+ return headerStore.get(name) ?? null;
747
+ },
748
+ getOrigin() {
749
+ return headerStore.get("origin") || headerStore.get("referer")?.split("/").slice(0, 3).join("/") || "";
750
+ },
751
+ getFramework() {
752
+ return "nextjs";
753
+ }
754
+ };
755
+ }
756
+
757
+ //#endregion
758
+ //#region src/server/config.ts
759
+ /**
760
+ * Framework-agnostic configuration types for Neon Auth
761
+ */
762
+ /**
763
+ * Validates cookie configuration meets security requirements
764
+ * @param cookies - The cookie configuration to validate
765
+ * @throws Error if secret is too short (< 32 characters)
766
+ */
767
+ function validateCookieConfig(cookies$1) {
768
+ if (!cookies$1.secret) throw new Error(ERRORS.MISSING_COOKIE_SECRET);
769
+ if (cookies$1.secret.length < 32) throw new Error(ERRORS.COOKIE_SECRET_TOO_SHORT);
770
+ if (cookies$1.sessionDataTtl !== void 0 && cookies$1.sessionDataTtl <= 0) throw new Error(ERRORS.INVALID_SESSION_DATA_TTL);
771
+ }
772
+
509
773
  //#endregion
510
774
  //#region src/server/proxy/request.ts
511
775
  const PROXY_HEADERS = [
@@ -613,7 +877,7 @@ const RESPONSE_HEADERS_ALLOWLIST = [
613
877
  */
614
878
  const handleAuthResponse = async (response, baseUrl, cookieConfig) => {
615
879
  const responseHeaders = prepareResponseHeaders(response, cookieConfig.domain);
616
- const sessionDataCookie = await mintSessionData(response.headers, baseUrl, cookieConfig);
880
+ const sessionDataCookie = await mintSessionDataFromResponse(response.headers, baseUrl, cookieConfig);
617
881
  if (sessionDataCookie) responseHeaders.append("Set-Cookie", sessionDataCookie);
618
882
  return new Response(response.body, {
619
883
  status: response.status,
@@ -625,81 +889,21 @@ const prepareResponseHeaders = (response, domain) => {
625
889
  const headers$1 = new Headers();
626
890
  for (const header of RESPONSE_HEADERS_ALLOWLIST) if (header === "set-cookie") {
627
891
  const cookies$1 = response.headers.getSetCookie();
628
- for (const cookieHeader of cookies$1) if (domain) {
892
+ for (const cookieHeader of cookies$1) {
629
893
  const parsedCookies = parseSetCookies(cookieHeader);
630
894
  for (const parsedCookie of parsedCookies) {
631
- parsedCookie.domain = domain;
895
+ parsedCookie.partitioned = void 0;
896
+ parsedCookie.sameSite = "lax";
897
+ if (domain) parsedCookie.domain = domain;
632
898
  headers$1.append("Set-Cookie", serializeSetCookie(parsedCookie));
633
899
  }
634
- } else headers$1.append("Set-Cookie", cookieHeader);
900
+ }
635
901
  } else {
636
902
  const value = response.headers.get(header);
637
903
  if (value) headers$1.set(header, value);
638
904
  }
639
905
  return headers$1;
640
906
  };
641
- async function mintSessionData(headers$1, baseUrl, cookieConfig) {
642
- const { secret, sessionDataTtl, domain } = cookieConfig;
643
- const sessionToken = headers$1.getSetCookie().find((cookie) => cookie.includes("session_token"));
644
- if (!sessionToken) return null;
645
- if (sessionToken.toLowerCase().includes("max-age=0")) return serializeSetCookie({
646
- name: NEON_AUTH_SESSION_DATA_COOKIE_NAME,
647
- value: "",
648
- path: "/",
649
- domain,
650
- httpOnly: true,
651
- secure: true,
652
- sameSite: "lax",
653
- maxAge: 0
654
- });
655
- try {
656
- const sessionData = await fetchSessionWithCookie(sessionToken, baseUrl);
657
- if (sessionData.session) {
658
- const { value: signedData, expiresAt } = await signSessionDataCookie(sessionData, secret, sessionDataTtl);
659
- return serializeSetCookie({
660
- name: NEON_AUTH_SESSION_DATA_COOKIE_NAME,
661
- value: signedData,
662
- path: "/",
663
- domain,
664
- httpOnly: true,
665
- secure: true,
666
- sameSite: "lax",
667
- maxAge: Math.floor((expiresAt.getTime() - Date.now()) / 1e3)
668
- });
669
- }
670
- } catch (error) {
671
- const errorMessage = error instanceof Error ? error.message : String(error);
672
- const errorContext = {
673
- error: errorMessage,
674
- setCookieHeaderLength: sessionToken?.length || 0
675
- };
676
- if (errorMessage.includes("session_token not found")) console.warn("[mintSessionData] Session token missing in set-cookie:", errorContext);
677
- else if (errorMessage.includes("Failed to fetch session data")) console.error("[mintSessionData] Upstream /get-session request failed:", errorContext);
678
- else if (errorMessage.includes("NEON_AUTH_COOKIE_SECRET")) console.error("[mintSessionData] Cookie secret configuration error:", errorContext);
679
- else if (errorMessage.includes("Invalid date")) console.error("[mintSessionData] Date parsing error:", errorContext);
680
- else console.error("[mintSessionData] Unexpected error:", {
681
- ...errorContext,
682
- ...process.env.NODE_ENV !== "production" && { stack: error instanceof Error ? error.stack : void 0 }
683
- });
684
- }
685
- return null;
686
- }
687
- async function fetchSessionWithCookie(setCookieHeader, baseUrl) {
688
- const sessionToken = parseSetCookies(setCookieHeader).find((c) => c.name.includes("session_token"));
689
- if (!sessionToken) throw new Error("session_token not found in set-cookie header");
690
- const response = await fetch(`${baseUrl}/get-session`, {
691
- headers: { Cookie: `${sessionToken.name}=${sessionToken.value}` },
692
- signal: AbortSignal.timeout(3e3)
693
- });
694
- if (!response.ok) throw new Error(`Failed to fetch session data: ${response.status} ${response.statusText}`);
695
- let body;
696
- try {
697
- body = await response.json();
698
- } catch (error) {
699
- throw new Error(`Failed to parse /get-session response as JSON: ${error instanceof Error ? error.message : String(error)}`);
700
- }
701
- return parseSessionData(body);
702
- }
703
907
 
704
908
  //#endregion
705
909
  //#region src/server/session/cache-handler.ts
@@ -707,38 +911,68 @@ async function fetchSessionWithCookie(setCookieHeader, baseUrl) {
707
911
  * Attempts to retrieve session data from cookie cache
708
912
  * Returns Response with session data if cache hit, null otherwise
709
913
  *
914
+ * If session_data cookie is missing or invalid, attempts to mint a new one
915
+ * from the session_token cookie (reactive minting).
916
+ *
710
917
  * This is the framework-agnostic session cache optimization used by API handlers.
711
918
  *
712
919
  * @param request - Standard Web API Request object
713
- * @param cookieSecret - Secret for validating signed session cookies
920
+ * @param baseUrl - Auth server base URL for upstream calls
921
+ * @param cookieConfig - Cookie configuration (secret, TTL, domain)
714
922
  * @returns Response with session data JSON if cache hit, null if miss/disabled
715
923
  */
716
- async function trySessionCache(request, cookieSecret) {
924
+ async function trySessionCache(request, baseUrl, cookieConfig) {
717
925
  if (new URL(request.url).searchParams.get("disableCookieCache") === "true") return null;
718
- if (!(request.headers.get("cookie") || "").includes(NEON_AUTH_SESSION_COOKIE_NAME)) return null;
926
+ const cookieHeader = request.headers.get("cookie") || "";
927
+ if (!cookieHeader.includes(NEON_AUTH_SESSION_COOKIE_NAME)) return null;
928
+ const hasSessionData = parseCookies(cookieHeader).has(NEON_AUTH_SESSION_DATA_COOKIE_NAME);
929
+ const mintAndReturn = async () => {
930
+ const sessionTokenCookie = extractSessionTokenCookie(cookieHeader);
931
+ if (!sessionTokenCookie) return null;
932
+ const sessionDataCookieString = await mintSessionDataFromToken(sessionTokenCookie, baseUrl, cookieConfig);
933
+ if (!sessionDataCookieString) return null;
934
+ try {
935
+ const sessionData = await fetchSessionWithCookie(sessionTokenCookie, baseUrl);
936
+ if (!sessionData.session) return null;
937
+ const response = Response.json(sessionData);
938
+ response.headers.set("Set-Cookie", sessionDataCookieString);
939
+ return response;
940
+ } catch (error) {
941
+ console.error("[trySessionCache] Failed to fetch session after minting cookie:", error);
942
+ return null;
943
+ }
944
+ };
945
+ if (!hasSessionData) return await mintAndReturn();
719
946
  try {
720
- const sessionData = await getSessionDataFromCookie(request, NEON_AUTH_SESSION_DATA_COOKIE_NAME, cookieSecret);
947
+ const sessionData = await getSessionDataFromCookie(request, NEON_AUTH_SESSION_DATA_COOKIE_NAME, cookieConfig.secret);
721
948
  if (sessionData && sessionData.session) return Response.json(sessionData);
949
+ return await mintAndReturn();
722
950
  } catch (error) {
723
951
  const errorMessage = error instanceof Error ? error.message : String(error);
724
952
  const errorName = error instanceof Error ? error.name : "Unknown";
725
- if (errorName === "JWTExpired") console.debug("[trySessionCache] Session cookie expired (expected):", {
953
+ if (errorName === "JWTExpired") console.debug("[trySessionCache] Session cookie expired, minting new one:", {
726
954
  error: errorMessage,
727
- errorType: errorName,
728
955
  url: request.url
729
956
  });
730
- else if (errorName === "JWTInvalid" || errorName === "JWTClaimValidationFailed") console.warn("[trySessionCache] Invalid session cookie (possible tampering):", {
957
+ else if (errorName === "JWTInvalid" || errorName === "JWTClaimValidationFailed") console.warn("[trySessionCache] Invalid session cookie, minting new one:", {
731
958
  error: errorMessage,
732
- errorType: errorName,
733
959
  url: request.url
734
960
  });
735
- else console.error("[trySessionCache] Unexpected cookie validation error:", {
961
+ else console.error("[trySessionCache] Unexpected validation error:", {
736
962
  error: errorMessage,
737
- errorType: errorName,
738
963
  url: request.url
739
964
  });
965
+ return await mintAndReturn();
740
966
  }
741
- return null;
967
+ }
968
+ /**
969
+ * Extract session_token cookie value from cookie header
970
+ * @internal
971
+ */
972
+ function extractSessionTokenCookie(cookieHeader) {
973
+ const sessionToken = parseCookies(cookieHeader).get(NEON_AUTH_SESSION_COOKIE_NAME);
974
+ if (!sessionToken) return null;
975
+ return `${NEON_AUTH_SESSION_COOKIE_NAME}=${sessionToken}`;
742
976
  }
743
977
 
744
978
  //#endregion
@@ -760,7 +994,11 @@ async function trySessionCache(request, cookieSecret) {
760
994
  async function handleAuthProxyRequest(config) {
761
995
  const { request, path, baseUrl, cookieSecret, sessionDataTtl, domain } = config;
762
996
  if (path === API_ENDPOINTS.getSession.path && request.method === API_ENDPOINTS.getSession.method) {
763
- const cachedResponse = await trySessionCache(request, cookieSecret);
997
+ const cachedResponse = await trySessionCache(request, baseUrl, {
998
+ secret: cookieSecret,
999
+ sessionDataTtl,
1000
+ domain
1001
+ });
764
1002
  if (cachedResponse) return cachedResponse;
765
1003
  }
766
1004
  return await handleAuthResponse(await handleAuthRequest(baseUrl, request, path), baseUrl, {
@@ -770,161 +1008,6 @@ async function handleAuthProxyRequest(config) {
770
1008
  });
771
1009
  }
772
1010
 
773
- //#endregion
774
- //#region src/server/client-factory.ts
775
- function createAuthServerInternal(config) {
776
- const { baseUrl, context: getContext, cookieSecret, sessionDataTtl, domain } = config;
777
- const fetchWithAuth = async (path, method, args) => {
778
- const ctx = await getContext();
779
- const cookies$1 = await ctx.getCookies();
780
- const origin = await ctx.getOrigin();
781
- const framework = ctx.getFramework();
782
- const url = new URL(path, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`);
783
- const { query, fetchOptions: _fetchOptions, ...body } = args || {};
784
- if (query && typeof query === "object") {
785
- const queryParams = query;
786
- for (const [key, value] of Object.entries(queryParams)) if (value !== void 0 && value !== null) url.searchParams.set(key, String(value));
787
- }
788
- const headers$1 = {
789
- Cookie: cookies$1,
790
- Origin: origin,
791
- [NEON_AUTH_SERVER_PROXY_HEADER]: framework
792
- };
793
- let requestBody;
794
- if (method === "POST") {
795
- headers$1["Content-Type"] = "application/json";
796
- requestBody = JSON.stringify(Object.keys(body).length > 0 ? body : {});
797
- }
798
- const response = await fetch(url.toString(), {
799
- method,
800
- headers: headers$1,
801
- body: requestBody
802
- });
803
- const setCookieHeaders = response.headers.getSetCookie();
804
- if (setCookieHeaders.length > 0) {
805
- for (const setCookieHeader of setCookieHeaders) {
806
- const parsedCookies = parseSetCookies(setCookieHeader);
807
- for (const cookie of parsedCookies) {
808
- const cookieOptions = domain ? {
809
- ...cookie,
810
- domain
811
- } : cookie;
812
- await ctx.setCookie(cookie.name, cookie.value, cookieOptions);
813
- }
814
- }
815
- try {
816
- const sessionDataCookie = await mintSessionData(response.headers, baseUrl, {
817
- secret: cookieSecret,
818
- sessionDataTtl,
819
- domain
820
- });
821
- if (sessionDataCookie) {
822
- const [parsedSessionData] = parseSetCookies(sessionDataCookie);
823
- if (parsedSessionData) await ctx.setCookie(parsedSessionData.name, parsedSessionData.value, parsedSessionData);
824
- }
825
- } catch (error) {
826
- console.error("[fetchWithAuth] Failed to mint session data cookie:", error);
827
- }
828
- }
829
- const responseData = await response.json().catch(() => null);
830
- if (!response.ok) return {
831
- data: null,
832
- error: {
833
- message: responseData?.message || response.statusText,
834
- status: response.status,
835
- statusText: response.statusText
836
- }
837
- };
838
- return {
839
- data: responseData,
840
- error: null
841
- };
842
- };
843
- const baseServer = createApiProxy(API_ENDPOINTS, fetchWithAuth);
844
- const originalGetSession = baseServer.getSession;
845
- baseServer.getSession = async (...args) => {
846
- const [data] = args;
847
- if (!(data?.query?.disableCookieCache === "true")) try {
848
- const cookiesString = await (await getContext()).getCookies();
849
- const hasSessionToken = cookiesString.includes(NEON_AUTH_SESSION_COOKIE_NAME);
850
- const sessionDataCookie = parseCookieValue(cookiesString, NEON_AUTH_SESSION_DATA_COOKIE_NAME);
851
- if (sessionDataCookie && hasSessionToken) {
852
- const result = await validateSessionData(sessionDataCookie, cookieSecret);
853
- if (result.valid && result.payload) return {
854
- data: result.payload,
855
- error: null
856
- };
857
- }
858
- } catch (error) {
859
- console.error("[auth.getSession] Cookie validation error:", error);
860
- }
861
- return originalGetSession(...args);
862
- };
863
- return baseServer;
864
- }
865
- function isEndpointConfig(value) {
866
- return typeof value === "object" && value !== null && "path" in value && "method" in value;
867
- }
868
- function createApiProxy(endpoints, fetchFn) {
869
- return new Proxy({}, {
870
- get(target, prop) {
871
- if (prop in target) return target[prop];
872
- const endpoint = endpoints[prop];
873
- if (!endpoint) return;
874
- if (isEndpointConfig(endpoint)) return (args) => fetchFn(endpoint.path, endpoint.method, args);
875
- return createApiProxy(endpoint, fetchFn);
876
- },
877
- set(target, prop, value) {
878
- target[prop] = value;
879
- return true;
880
- }
881
- });
882
- }
883
-
884
- //#endregion
885
- //#region src/next/server/adapter.ts
886
- /**
887
- * Creates a Next.js-specific RequestContext that reads cookies and headers
888
- * from next/headers and handles cookie setting.
889
- */
890
- async function createNextRequestContext() {
891
- const cookieStore = await cookies();
892
- const headerStore = await headers();
893
- return {
894
- getCookies() {
895
- return extractNeonAuthCookies(headerStore);
896
- },
897
- setCookie(name, value, options) {
898
- cookieStore.set(name, value, options);
899
- },
900
- getHeader(name) {
901
- return headerStore.get(name) ?? null;
902
- },
903
- getOrigin() {
904
- return headerStore.get("origin") || headerStore.get("referer")?.split("/").slice(0, 3).join("/") || "";
905
- },
906
- getFramework() {
907
- return "nextjs";
908
- }
909
- };
910
- }
911
-
912
- //#endregion
913
- //#region src/server/config.ts
914
- /**
915
- * Framework-agnostic configuration types for Neon Auth
916
- */
917
- /**
918
- * Validates cookie configuration meets security requirements
919
- * @param cookies - The cookie configuration to validate
920
- * @throws Error if secret is too short (< 32 characters)
921
- */
922
- function validateCookieConfig(cookies$1) {
923
- if (!cookies$1.secret) throw new Error(ERRORS.MISSING_COOKIE_SECRET);
924
- if (cookies$1.secret.length < 32) throw new Error(ERRORS.COOKIE_SECRET_TOO_SHORT);
925
- if (cookies$1.sessionDataTtl !== void 0 && cookies$1.sessionDataTtl <= 0) throw new Error(ERRORS.INVALID_SESSION_DATA_TTL);
926
- }
927
-
928
1011
  //#endregion
929
1012
  //#region src/next/server/handler.ts
930
1013
  /**
@@ -1108,6 +1191,7 @@ async function processAuthMiddleware(config) {
1108
1191
  session: null,
1109
1192
  user: null
1110
1193
  };
1194
+ let sessionCookies = [];
1111
1195
  if (hasSessionToken) {
1112
1196
  const sessionResponse = await handleAuthProxyRequest({
1113
1197
  request,
@@ -1121,10 +1205,12 @@ async function processAuthMiddleware(config) {
1121
1205
  const data = await sessionResponse.json().catch(() => null);
1122
1206
  if (data) sessionData = data;
1123
1207
  }
1208
+ sessionCookies = sessionResponse.headers.getSetCookie();
1124
1209
  }
1125
1210
  if (checkSessionRequired(pathname, skipRoutes, loginUrl, sessionData).allowed) return {
1126
1211
  action: "allow",
1127
- headers: { [NEON_AUTH_HEADER_MIDDLEWARE_NAME]: "true" }
1212
+ headers: { [NEON_AUTH_HEADER_MIDDLEWARE_NAME]: "true" },
1213
+ cookies: sessionCookies
1128
1214
  };
1129
1215
  const cookies$1 = [];
1130
1216
  if (hasStaleSessionData) cookies$1.push(serializeSetCookie({
@@ -1199,7 +1285,9 @@ function neonAuthMiddleware(config) {
1199
1285
  case "allow": {
1200
1286
  const headers$1 = new Headers(request.headers);
1201
1287
  if (result.headers) for (const [key, value] of Object.entries(result.headers)) headers$1.set(key, value);
1202
- return NextResponse.next({ request: { headers: headers$1 } });
1288
+ const response = NextResponse.next({ request: { headers: headers$1 } });
1289
+ if (result.cookies) for (const cookie of result.cookies) response.headers.append("Set-Cookie", cookie);
1290
+ return response;
1203
1291
  }
1204
1292
  case "redirect_oauth": {
1205
1293
  const oauthHeaders = new Headers();
@@ -1,4 +1,4 @@
1
- import "../../adapter-core-CnrOXh1T.mjs";
2
- import { n as BetterAuthReactAdapterInstance, r as BetterAuthReactAdapterOptions, t as BetterAuthReactAdapter } from "../../better-auth-react-adapter-DNi5PC5D.mjs";
3
- import "../../index-CPnFzULh.mjs";
1
+ import "../../adapter-core-B9uDhoYq.mjs";
2
+ import { n as BetterAuthReactAdapterInstance, r as BetterAuthReactAdapterOptions, t as BetterAuthReactAdapter } from "../../better-auth-react-adapter-BO4jLN4H.mjs";
3
+ import "../../index-UW23fDSn.mjs";
4
4
  export { BetterAuthReactAdapter, BetterAuthReactAdapterInstance, BetterAuthReactAdapterOptions };
@@ -1,4 +1,4 @@
1
- import "../../adapter-core-CtmnMMJ7.mjs";
2
- import { t as BetterAuthReactAdapter } from "../../better-auth-react-adapter-Dv-o6A6O.mjs";
1
+ import "../../adapter-core-D00qcqMo.mjs";
2
+ import { t as BetterAuthReactAdapter } from "../../better-auth-react-adapter-Xdj-69i9.mjs";
3
3
 
4
4
  export { BetterAuthReactAdapter };