Skip to content

Commit 62861b9

Browse files
committed
Fix SSO url parse
1 parent af29a20 commit 62861b9

1 file changed

Lines changed: 22 additions & 29 deletions

File tree

src/components/Login.tsx

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -44,45 +44,38 @@ export function Login() {
4444

4545
// Parse SSO redirect style: {server}/access_token=...&refresh_token=...
4646
useEffect(() => {
47-
// Detect tokens embedded after origin (no question mark) e.g. https://srv/access_token=XXX&refresh_token=YYY
48-
// Or possibly inside hash.
4947
try {
5048
const loc = window.location;
51-
const path = loc.pathname.startsWith("/")
52-
? loc.pathname.slice(1)
53-
: loc.pathname;
49+
const search = loc.search.startsWith("?") ? loc.search.substring(1) : loc.search;
50+
const path = loc.pathname.startsWith("/") ? loc.pathname.slice(1) : loc.pathname;
5451
const hash = loc.hash.startsWith("#") ? loc.hash.slice(1) : loc.hash;
55-
const candidate = path.includes("access_token=") ? path : hash;
56-
if (!candidate) return;
57-
if (!/access_token=/.test(candidate)) return;
58-
// Interpret as key=value pairs separated by & possibly with leading segment (e.g., access_token=...&refresh_token=...)
59-
const pairs = candidate.split("&").filter(Boolean);
60-
const data: Record<string, string> = {};
61-
for (const p of pairs) {
62-
const eq = p.indexOf("=");
63-
if (eq === -1) continue;
64-
const k = decodeURIComponent(p.slice(0, eq));
65-
const v = decodeURIComponent(p.slice(eq + 1));
66-
data[k] = v;
67-
}
68-
if (!data.access_token) return;
69-
// Determine server base: remove the trailing candidate part from URL if it's at pathname
70-
const base = window.location.origin;
52+
53+
// Priority order: query string (?access_token=...), then path style, then hash fragment.
54+
let candidate = "";
55+
if (/access_token=/.test(search)) candidate = search;
56+
else if (/access_token=/.test(path)) candidate = path;
57+
else if (/access_token=/.test(hash)) candidate = hash;
58+
if (!candidate) return; // no tokens present
59+
60+
const params = new URLSearchParams(candidate.replace(/^[^?]*\?/, ""));
61+
const access = params.get("access_token") || "";
62+
const refresh = params.get("refresh_token") || undefined;
63+
if (!access) return;
64+
65+
const base = window.location.origin; // assume same origin the user entered for SSO
7166
(async () => {
7267
try {
73-
await loginWithTokens(base, {
74-
access_token: data.access_token,
75-
refresh_token: data.refresh_token,
76-
});
77-
// Clean URL (remove tokens) then navigate
78-
window.history.replaceState({}, document.title, base + "/login");
68+
await loginWithTokens(base, { access_token: access, refresh_token: refresh });
69+
// Scrub sensitive tokens from URL: go to /login (or /library directly after navigation) without query/hash.
70+
const cleanUrl = base + "/login";
71+
window.history.replaceState({}, document.title, cleanUrl);
7972
navigate("/library", { replace: true });
8073
} catch {
81-
// ignore - error shown via context
74+
// ignore - context will show error
8275
}
8376
})();
8477
} catch {
85-
// ignore parsing errors
78+
// swallow parsing errors silently
8679
}
8780
}, [loginWithTokens, navigate]);
8881

0 commit comments

Comments
 (0)