diff --git a/packages/auth/src/config.ts b/packages/auth/src/config.ts index 09d6234..a3fd79e 100644 --- a/packages/auth/src/config.ts +++ b/packages/auth/src/config.ts @@ -96,18 +96,16 @@ export const authConfig: NextAuthConfig = { const { createTransport } = await import("nodemailer"); const transport = createTransport(provider.server); - // Parse the NextAuth callback URL to extract token and callbackUrl const parsedUrl = new URL(url); const host = parsedUrl.host; - const token = parsedUrl.searchParams.get("token") || ""; - const callbackUrl = parsedUrl.searchParams.get("callbackUrl") || "/dashboard"; // Build an intermediate /verify URL that prevents email scanners - // from consuming the one-time token via pre-fetch GET requests + // from consuming the one-time token via pre-fetch GET requests. + // We pass the ENTIRE original callback URL encoded to avoid + // dropping any parameters NextAuth needs internally. const verifyUrl = new URL("/verify", parsedUrl.origin); - verifyUrl.searchParams.set("token", token); + verifyUrl.searchParams.set("callback", Buffer.from(url).toString("base64")); verifyUrl.searchParams.set("email", identifier); - verifyUrl.searchParams.set("callbackUrl", callbackUrl); const safeUrl = verifyUrl.toString(); const result = await transport.sendMail({ diff --git a/sites/mainweb/app/(portal)/verify/page.tsx b/sites/mainweb/app/(portal)/verify/page.tsx index b489255..b64e07c 100644 --- a/sites/mainweb/app/(portal)/verify/page.tsx +++ b/sites/mainweb/app/(portal)/verify/page.tsx @@ -8,20 +8,22 @@ function VerifyContent() { const searchParams = useSearchParams(); const [verifying, setVerifying] = useState(false); - // Build the actual NextAuth callback URL from the search params - const callbackUrl = searchParams?.get('callbackUrl') || '/dashboard'; - const token = searchParams?.get('token') || ''; + // The full NextAuth callback URL is base64-encoded in the 'callback' param + const encodedCallback = searchParams?.get('callback') || ''; const email = searchParams?.get('email') || ''; + let callbackUrl = ''; + try { + callbackUrl = atob(encodedCallback); + } catch { + // invalid base64 + } + const handleVerify = () => { + if (!callbackUrl) return; setVerifying(true); - // Redirect to the actual NextAuth email callback - const params = new URLSearchParams({ - callbackUrl, - token, - email, - }); - window.location.href = `/api/auth/callback/nodemailer?${params.toString()}`; + // Redirect to the exact original NextAuth callback URL + window.location.href = callbackUrl; }; return ( @@ -55,16 +57,16 @@ function VerifyContent() {
- {!token && ( + {!callbackUrl && (

- Error: No verification token found. Please request a new sign-in link. + Error: Invalid or missing verification link. Please request a new sign-in link.

)}