From df2841cf36739b5ac808d4678cdc048983b13cbb Mon Sep 17 00:00:00 2001 From: Peter White <1788320+peterwhite@users.noreply.github.com> Date: Mon, 28 Sep 2026 17:43:23 +0200 Subject: [PATCH] Don't leak the internal route into the site auth login link (#4642) --- .changeset/site-auth-login-location.md | 5 +++++ .../src/components/SiteAuth/SiteAuthLoginLink.tsx | 11 ++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 .changeset/site-auth-login-location.md diff --git a/.changeset/site-auth-login-location.md b/.changeset/site-auth-login-location.md new file mode 100644 index 000000000..f453c791f --- /dev/null +++ b/.changeset/site-auth-login-location.md @@ -0,0 +1,5 @@ +--- +"gitbook": patch +--- + +Fix the site auth login link sometimes redirecting back to an internal URL after login. diff --git a/packages/gitbook/src/components/SiteAuth/SiteAuthLoginLink.tsx b/packages/gitbook/src/components/SiteAuth/SiteAuthLoginLink.tsx index 52cfd6c10..1be3301ec 100644 --- a/packages/gitbook/src/components/SiteAuth/SiteAuthLoginLink.tsx +++ b/packages/gitbook/src/components/SiteAuth/SiteAuthLoginLink.tsx @@ -4,6 +4,7 @@ import { usePathname, useSearchParams } from 'next/navigation'; import { useMemo } from 'react'; import type React from 'react'; +import { useIsMounted } from '../hooks/useIsMounted'; import { Button, type ButtonProps } from '../primitives/Button'; import { DropdownMenuItem } from '../primitives/DropdownMenu'; import { Link, type LinkInsightsProps, type LinkProps } from '../primitives/Link'; @@ -16,9 +17,17 @@ function useSiteAuthLoginHrefWithLocation(href: string) { const rawPathname = usePathname(); const searchParams = useSearchParams(); const currentSearch = searchParams?.toString(); - const pathname = rawPathname ?? '/'; + // On the server, usePathname() returns the internal rewritten route (/sites/…, which includes + // the site API token), so the location is only added once mounted. + // https://nextjs.org/docs/app/api-reference/functions/use-pathname#avoid-hydration-mismatch-with-rewrites + const isMounted = useIsMounted(); + const pathname = isMounted ? (rawPathname ?? '/') : null; return useMemo(() => { + if (pathname === null) { + return href; + } + const baseURL = typeof window !== 'undefined' ? window.location.origin : 'http://localhost'; const resolved = URL.canParse(href) ? new URL(href) : new URL(href, baseURL); const siteBasePath = removeTrailingSlash(