diff options
| author | stuppie | 2026-08-31 16:52:15 -0600 |
|---|---|---|
| committer | stuppie | 2026-08-31 16:52:15 -0600 |
| commit | 3f8d178d38686c1a5d71d94ebccdb61701469e95 (patch) | |
| tree | 435707789cc0d1eb3c8670e4ab4bbae11d773285 /jb-ui | |
| parent | 12f6fee851b68e86af658dfa17e4a0daed457dd1 (diff) | |
| download | amt-jb-3f8d178d38686c1a5d71d94ebccdb61701469e95.tar.gz amt-jb-3f8d178d38686c1a5d71d94ebccdb61701469e95.zip | |
working on magic token and session token auth
Diffstat (limited to 'jb-ui')
| -rw-r--r-- | jb-ui/src/JBApp.tsx | 4 | ||||
| -rw-r--r-- | jb-ui/src/pages/MagicLink.tsx | 44 |
2 files changed, 47 insertions, 1 deletions
diff --git a/jb-ui/src/JBApp.tsx b/jb-ui/src/JBApp.tsx index 76e3f29..ef23b3b 100644 --- a/jb-ui/src/JBApp.tsx +++ b/jb-ui/src/JBApp.tsx @@ -19,6 +19,7 @@ import { setAssignmentID, setProductUserID, setTurkSubmitTo } from "@/models/app import { addEvent } from "@/models/grlEventsSlice"; import { addStatsData } from "@/models/grlStatsSlice"; import Home from "@/pages/Home"; +import MagicLink from "@/pages/MagicLink"; import Preview from "@/pages/Preview"; import Result from "@/pages/Result"; import Work from "@/pages/Work"; @@ -193,6 +194,7 @@ function JBApp() { return ( <BrowserRouter basename={routeBasename}> <Routes> + <Route path="/auth/magic-link/" element={<MagicLink />} /> <Route element={<QueryParamProcessor />}> <Route element={<Layout />}> <Route path="/" element={<Home />} /> @@ -206,4 +208,4 @@ function JBApp() { ) } -export default JBApp;
\ No newline at end of file +export default JBApp; diff --git a/jb-ui/src/pages/MagicLink.tsx b/jb-ui/src/pages/MagicLink.tsx new file mode 100644 index 0000000..cf7f87b --- /dev/null +++ b/jb-ui/src/pages/MagicLink.tsx @@ -0,0 +1,44 @@ +import { useEffect, useRef, useState } from "react"; + +type ExchangeState = "working" | "failed" | "missing"; + +const MagicLink = function () { + const started = useRef(false); + const [state, setState] = useState<ExchangeState>("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/magic-link/exchange", { + method: "POST", + credentials: "include", + headers: {"Content-Type": "application/json"}, + body: JSON.stringify({token}), + }).then((response) => { + if (!response.ok) throw new Error("Magic-link exchange failed"); + window.location.replace("/"); + }).catch(() => setState("failed")); + }, []); + + if (state === "missing") { + return <p>This login link is missing its token.</p>; + } + if (state === "failed") { + return <p>This login link is invalid or has expired.</p>; + } + return <p>Signing you in…</p>; +}; + +export default MagicLink; |
