Encode sign-in mail as base64 so webmail cannot mangle the verify token.

Quoted-printable still rewrote token= as token=3D in the raw MIME, which some clients never decode. Distinguish a missing token from a real expiry, and keep links valid for 60 minutes.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
adilallo
2026-09-01 17:07:00 -06:00
co-authored by Cursor
parent fa928d1b2c
commit f780eac1fa
9 changed files with 148 additions and 25 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ import { getPublicOrigin } from "../../../../../lib/server/publicOrigin";
import { magicLinkRequestBodySchema } from "../../../../../lib/server/validation/createFlowSchemas";
import { jsonFromZodError } from "../../../../../lib/server/validation/zodHttp";
const MAGIC_LINK_TTL_MS = 15 * 60 * 1000;
const MAGIC_LINK_TTL_MS = 60 * 60 * 1000;
const EMAIL_MIN_INTERVAL_MS = 60 * 1000;
const IP_MIN_INTERVAL_MS = 20 * 1000;
const SCOPE = "auth.magicLink.request";
+9 -1
View File
@@ -54,7 +54,15 @@ export async function GET(request: NextRequest) {
where: { tokenHash },
});
if (!row || row.expiresAt < new Date()) {
if (!row) {
return redirectWithRequestId(
request,
"/login?error=invalid_link",
requestId,
);
}
if (row.expiresAt < new Date()) {
return redirectWithRequestId(
request,
"/login?error=expired_link",
+1 -1
View File
@@ -25,7 +25,7 @@ import { readLimitedJson } from "../../../../../lib/server/validation/requestBod
import { emailChangeRequestBodySchema } from "../../../../../lib/server/validation/userEmailChangeSchemas";
import { jsonFromZodError } from "../../../../../lib/server/validation/zodHttp";
const EMAIL_CHANGE_TTL_MS = 15 * 60 * 1000;
const EMAIL_CHANGE_TTL_MS = 60 * 60 * 1000;
const EMAIL_MIN_INTERVAL_MS = 60 * 1000;
const IP_MIN_INTERVAL_MS = 20 * 1000;
const SCOPE = "user.emailChange.request";