From d7f2bd71b1546ba4142f6d4631bba5212b25f873 Mon Sep 17 00:00:00 2001 From: Max Nanis Date: Sun, 13 Sep 2026 13:15:03 -0700 Subject: "/auth/link-amt/" to POST --- jb-ui/src/JBApp.tsx | 2 ++ jb-ui/src/pages/MagicAMTLink.tsx | 46 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 jb-ui/src/pages/MagicAMTLink.tsx diff --git a/jb-ui/src/JBApp.tsx b/jb-ui/src/JBApp.tsx index c55cd73..083e52d 100644 --- a/jb-ui/src/JBApp.tsx +++ b/jb-ui/src/JBApp.tsx @@ -33,6 +33,7 @@ import { addCashoutMethods } from "@/models/cashoutMethodsSlice"; import { addEvent } from "@/models/grlEventsSlice"; import { addStatsData } from "@/models/grlStatsSlice"; import MagicLink from "@/pages/MagicLink"; +import MagicAMTLink from "@/pages/MagicAMTLink"; import Result from "@/pages/Result"; import clsx from "clsx"; @@ -274,6 +275,7 @@ function JBApp() { }> } /> } /> + } /> } /> } /> diff --git a/jb-ui/src/pages/MagicAMTLink.tsx b/jb-ui/src/pages/MagicAMTLink.tsx new file mode 100644 index 0000000..fdd7437 --- /dev/null +++ b/jb-ui/src/pages/MagicAMTLink.tsx @@ -0,0 +1,46 @@ +import { useEffect, useRef, useState } from "react"; + +type ExchangeState = "working" | "failed" | "missing"; + +const MagicLink = function () { + const started = useRef(false); + const [state, setState] = useState("working"); + + useEffect(() => { + // React Strict Mode runs effects twice in development. Never redeem twice. + if (started.current) return; + started.current = true; + + const params = new URLSearchParams(window.location.search); + const token = params.get("token"); + if (!token) { + setState("missing"); + return; + } + + // Keep the credential out of browser history and subsequent Referer headers. + window.history.replaceState({}, "", window.location.pathname); + + void fetch("/auth/link-amt/exchange/", { + method: "POST", + credentials: "include", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ token: token }), + }) + .then((response) => { + if (!response.ok) throw new Error("Magic-link exchange failed"); + window.location.replace("/"); + }) + .catch(() => setState("failed")); + }, []); + + if (state === "missing") { + return

This login link is missing its token.

; + } + if (state === "failed") { + return

This login link is invalid or has expired.

; + } + return

Signing you in…

; +}; + +export default MagicLink; -- cgit v1.2.3