mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-08 22:21:35 +00:00
fix(ui): send onboarding claim with configured litellm_key_header_name
This commit is contained in:
parent
4edf8f1551
commit
71982f63dc
2 changed files with 76 additions and 6 deletions
|
|
@ -5,17 +5,14 @@ import { OnboardingForm } from "./OnboardingForm";
|
|||
|
||||
const mockUseOnboardingCredentials = vi.fn();
|
||||
const mockClaimToken = vi.fn();
|
||||
const mockJwtDecode = vi.fn();
|
||||
|
||||
vi.mock("next/navigation", () => ({
|
||||
useSearchParams: () => new URLSearchParams("invitation_id=inv-123"),
|
||||
}));
|
||||
|
||||
vi.mock("jwt-decode", () => ({
|
||||
jwtDecode: vi.fn(() => ({
|
||||
user_email: "alice@example.com",
|
||||
user_id: "user-1",
|
||||
key: "access-tok",
|
||||
})),
|
||||
jwtDecode: (...args: unknown[]) => mockJwtDecode(...args),
|
||||
}));
|
||||
|
||||
vi.mock("@/app/(dashboard)/hooks/onboarding/useOnboarding", () => ({
|
||||
|
|
@ -23,8 +20,14 @@ vi.mock("@/app/(dashboard)/hooks/onboarding/useOnboarding", () => ({
|
|||
useClaimOnboardingToken: () => ({ mutate: mockClaimToken, isPending: false }),
|
||||
}));
|
||||
|
||||
let currentAuthHeaderName = "Authorization";
|
||||
|
||||
vi.mock("@/components/networking", () => ({
|
||||
getProxyBaseUrl: vi.fn(() => ""),
|
||||
setGlobalLitellmHeaderName: (headerName: string) => {
|
||||
currentAuthHeaderName = headerName;
|
||||
},
|
||||
getGlobalLitellmHeaderName: () => currentAuthHeaderName,
|
||||
}));
|
||||
|
||||
vi.mock("./OnboardingLoadingView", () => ({
|
||||
|
|
@ -60,6 +63,12 @@ vi.mock("./OnboardingFormBody", () => ({
|
|||
describe("OnboardingForm", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
currentAuthHeaderName = "Authorization";
|
||||
mockJwtDecode.mockReturnValue({
|
||||
user_email: "alice@example.com",
|
||||
user_id: "user-1",
|
||||
key: "access-tok",
|
||||
});
|
||||
document.cookie = "token=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
|
||||
document.cookie = "token=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/ui";
|
||||
sessionStorage.clear();
|
||||
|
|
@ -166,6 +175,62 @@ describe("OnboardingForm", () => {
|
|||
cookieSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("should send the claim request with the proxy's custom auth header name", async () => {
|
||||
mockJwtDecode.mockReturnValue({
|
||||
user_email: "alice@example.com",
|
||||
user_id: "user-1",
|
||||
key: "access-tok",
|
||||
auth_header_name: "x-litellm-api-key",
|
||||
});
|
||||
mockUseOnboardingCredentials.mockReturnValue({
|
||||
data: { token: "fake-jwt-token" },
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
});
|
||||
|
||||
// The onboarding page has no session yet, so the only source for a custom
|
||||
// `litellm_key_header_name` is the onboarding token's own claims; without
|
||||
// propagating it the claim lands in `Authorization` and the proxy answers
|
||||
// "Missing onboarding session for invitation link."
|
||||
const { getGlobalLitellmHeaderName } = await import("@/components/networking");
|
||||
const headerNameAtClaimTime: string[] = [];
|
||||
mockClaimToken.mockImplementation((_params, options) => {
|
||||
headerNameAtClaimTime.push(getGlobalLitellmHeaderName());
|
||||
options.onSuccess({ token: "NEW_USER_TOKEN" });
|
||||
});
|
||||
|
||||
render(<OnboardingForm variant="signup" />);
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(screen.getByRole("button", { name: "Submit" }));
|
||||
});
|
||||
|
||||
expect(headerNameAtClaimTime).toEqual(["x-litellm-api-key"]);
|
||||
});
|
||||
|
||||
it("should keep the default auth header name when the onboarding token has no custom header claim", async () => {
|
||||
mockUseOnboardingCredentials.mockReturnValue({
|
||||
data: { token: "fake-jwt-token" },
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
});
|
||||
|
||||
const { getGlobalLitellmHeaderName } = await import("@/components/networking");
|
||||
const headerNameAtClaimTime: string[] = [];
|
||||
mockClaimToken.mockImplementation((_params, options) => {
|
||||
headerNameAtClaimTime.push(getGlobalLitellmHeaderName());
|
||||
options.onSuccess({ token: "NEW_USER_TOKEN" });
|
||||
});
|
||||
|
||||
render(<OnboardingForm variant="signup" />);
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(screen.getByRole("button", { name: "Submit" }));
|
||||
});
|
||||
|
||||
expect(headerNameAtClaimTime).toEqual(["Authorization"]);
|
||||
});
|
||||
|
||||
it("should show claim error when claim response is missing final token", async () => {
|
||||
mockUseOnboardingCredentials.mockReturnValue({
|
||||
data: { token: "fake-jwt-token" },
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import React from "react";
|
|||
import { useSearchParams } from "next/navigation";
|
||||
import { jwtDecode } from "jwt-decode";
|
||||
import { useOnboardingCredentials, useClaimOnboardingToken } from "@/app/(dashboard)/hooks/onboarding/useOnboarding";
|
||||
import { getProxyBaseUrl } from "@/components/networking";
|
||||
import { getProxyBaseUrl, setGlobalLitellmHeaderName } from "@/components/networking";
|
||||
import { clearTokenCookies, storeLoginToken } from "@/utils/cookieUtils";
|
||||
import { OnboardingLoadingView } from "./OnboardingLoadingView";
|
||||
import { OnboardingErrorView } from "./OnboardingErrorView";
|
||||
|
|
@ -30,12 +30,17 @@ export function OnboardingForm({ variant }: OnboardingFormProps) {
|
|||
const userEmail: string = decoded?.user_email ?? "";
|
||||
const userId: string | null = decoded?.user_id ?? null;
|
||||
const accessToken: string | null = decoded?.key ?? null;
|
||||
const authHeaderName: string | null = decoded?.auth_header_name ?? null;
|
||||
|
||||
const handleSubmit = (formValues: { password: string }) => {
|
||||
if (!accessToken || !userId || !inviteId) return;
|
||||
|
||||
setClaimError(null);
|
||||
|
||||
if (authHeaderName) {
|
||||
setGlobalLitellmHeaderName(authHeaderName);
|
||||
}
|
||||
|
||||
claimToken(
|
||||
{ accessToken, inviteId, userId, password: formValues.password },
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue