mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
feat: add exchangeLoginCode for SSO code exchange, update LoginPage
- Add exchangeLoginCode() to networking.tsx for SSO callback - LoginPage detects ?code= from SSO redirect, exchanges for JWT - Keep backwards compat for legacy ?token= flow
This commit is contained in:
parent
0e3705d63a
commit
7ed5692597
2 changed files with 40 additions and 3 deletions
|
|
@ -3,7 +3,7 @@
|
|||
import { useLogin } from "@/app/(dashboard)/hooks/login/useLogin";
|
||||
import { useUIConfig } from "@/app/(dashboard)/hooks/uiConfig/useUIConfig";
|
||||
import LoadingScreen from "@/components/common_components/LoadingScreen";
|
||||
import { getProxyBaseUrl, switchToWorkerUrl } from "@/components/networking";
|
||||
import { exchangeLoginCode, getProxyBaseUrl, switchToWorkerUrl } from "@/components/networking";
|
||||
import { clearTokenCookies, getCookie } from "@/utils/cookieUtils";
|
||||
import { isJwtExpired } from "@/utils/jwtUtils";
|
||||
import { consumeReturnUrl, getReturnUrl, isValidReturnUrl } from "@/utils/returnUrlUtils";
|
||||
|
|
@ -43,12 +43,25 @@ function LoginPageContent() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Cross-origin SSO: worker redirected back with token in URL
|
||||
// Cross-origin SSO: worker redirected back with a single-use code.
|
||||
// Exchange it for the JWT via the worker's /v3/login/exchange endpoint.
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const ssoCode = params.get("code");
|
||||
if (ssoCode) {
|
||||
const workerUrl = localStorage.getItem("litellm_worker_url");
|
||||
exchangeLoginCode(ssoCode, workerUrl).then(() => {
|
||||
params.delete("code");
|
||||
const cleanSearch = params.toString();
|
||||
window.history.replaceState(null, "", window.location.pathname + (cleanSearch ? `?${cleanSearch}` : ""));
|
||||
router.replace("/ui/?login=success");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Backwards compat: handle direct token in URL (legacy flow)
|
||||
const urlToken = params.get("token");
|
||||
if (urlToken && !isJwtExpired(urlToken)) {
|
||||
document.cookie = `token=${urlToken}; path=/; SameSite=Lax`;
|
||||
// Strip token from URL to keep it out of browser history
|
||||
params.delete("token");
|
||||
const cleanSearch = params.toString();
|
||||
window.history.replaceState(
|
||||
|
|
|
|||
|
|
@ -9100,6 +9100,30 @@ export const loginCall = async (username: string, password: string, useV3?: bool
|
|||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Exchange a single-use login code for a JWT token.
|
||||
* Used by the SSO callback when the worker redirects back with ?code=.
|
||||
*/
|
||||
export const exchangeLoginCode = async (code: string, workerBaseUrl?: string | null): Promise<string> => {
|
||||
const base = workerBaseUrl || getProxyBaseUrl();
|
||||
const response = await fetch(`${base}/v3/login/exchange`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ code }),
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(deriveErrorMessage(errorData));
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (data.token) {
|
||||
document.cookie = `token=${data.token}; path=/; SameSite=Lax`;
|
||||
}
|
||||
return data.token;
|
||||
};
|
||||
|
||||
export const getUiSettings = async () => {
|
||||
const proxyBaseUrl = getProxyBaseUrl();
|
||||
const url = proxyBaseUrl ? `${proxyBaseUrl}/get/ui_settings` : `/get/ui_settings`;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue