aboutsummaryrefslogtreecommitdiff
path: root/jb-ui/src/pages
diff options
context:
space:
mode:
authorstuppie2026-08-31 16:52:15 -0600
committerstuppie2026-08-31 16:52:15 -0600
commit3f8d178d38686c1a5d71d94ebccdb61701469e95 (patch)
tree435707789cc0d1eb3c8670e4ab4bbae11d773285 /jb-ui/src/pages
parent12f6fee851b68e86af658dfa17e4a0daed457dd1 (diff)
downloadamt-jb-3f8d178d38686c1a5d71d94ebccdb61701469e95.tar.gz
amt-jb-3f8d178d38686c1a5d71d94ebccdb61701469e95.zip
working on magic token and session token auth
Diffstat (limited to 'jb-ui/src/pages')
-rw-r--r--jb-ui/src/pages/MagicLink.tsx44
1 files changed, 44 insertions, 0 deletions
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;