mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-07 08:26:10 +00:00
Extract shared PKCE helpers into src/utils/pkce.ts
Deduplicates base64UrlEncode, generateCodeVerifier, and generateCodeChallenge which were copy-pasted across useMcpOAuthFlow and useUserMcpOAuthFlow hooks.
This commit is contained in:
parent
72a461ba4a
commit
5aba1841cc
3 changed files with 22 additions and 40 deletions
|
|
@ -11,6 +11,7 @@ import {
|
|||
serverRootPath,
|
||||
} from "@/components/networking";
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
import { generateCodeChallenge, generateCodeVerifier } from "@/utils/pkce";
|
||||
import { getSecureItem, setSecureItem } from "@/utils/secureStorage";
|
||||
|
||||
export type McpOAuthStatus = "idle" | "authorizing" | "exchanging" | "success" | "error";
|
||||
|
|
@ -34,25 +35,6 @@ interface UseMcpOAuthFlowResult {
|
|||
tokenResponse: Record<string, any> | null;
|
||||
}
|
||||
|
||||
const base64UrlEncode = (buffer: ArrayBuffer) => {
|
||||
const bytes = new Uint8Array(buffer);
|
||||
let binary = "";
|
||||
bytes.forEach((b) => (binary += String.fromCharCode(b)));
|
||||
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
||||
};
|
||||
|
||||
const generateCodeVerifier = () => {
|
||||
const array = new Uint8Array(32);
|
||||
window.crypto.getRandomValues(array);
|
||||
return base64UrlEncode(array.buffer);
|
||||
};
|
||||
|
||||
const generateCodeChallenge = async (verifier: string) => {
|
||||
const data = new TextEncoder().encode(verifier);
|
||||
const digest = await window.crypto.subtle.digest("SHA-256", data);
|
||||
return base64UrlEncode(digest);
|
||||
};
|
||||
|
||||
export const useMcpOAuthFlow = ({
|
||||
accessToken,
|
||||
getCredentials,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import {
|
|||
} from "@/components/networking";
|
||||
import NotificationsManager from "@/components/molecules/notifications_manager";
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
import { generateCodeChallenge, generateCodeVerifier } from "@/utils/pkce";
|
||||
import { getSecureItem, setSecureItem } from "@/utils/secureStorage";
|
||||
|
||||
export type UserMcpOAuthStatus = "idle" | "authorizing" | "exchanging" | "success" | "error";
|
||||
|
|
@ -60,25 +61,6 @@ type StoredFlowState = {
|
|||
scopes?: string[];
|
||||
};
|
||||
|
||||
const b64url = (buf: ArrayBuffer) => {
|
||||
const bytes = new Uint8Array(buf);
|
||||
let s = "";
|
||||
bytes.forEach((b) => (s += String.fromCharCode(b)));
|
||||
return btoa(s).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
||||
};
|
||||
|
||||
const genVerifier = () => {
|
||||
const arr = new Uint8Array(32);
|
||||
window.crypto.getRandomValues(arr);
|
||||
return b64url(arr.buffer);
|
||||
};
|
||||
|
||||
const genChallenge = async (verifier: string) => {
|
||||
const data = new TextEncoder().encode(verifier);
|
||||
const digest = await window.crypto.subtle.digest("SHA-256", data);
|
||||
return b64url(digest);
|
||||
};
|
||||
|
||||
const setStorage = (key: string, value: string) => {
|
||||
setSecureItem(key, value);
|
||||
};
|
||||
|
|
@ -144,8 +126,8 @@ export const useUserMcpOAuthFlow = ({
|
|||
}
|
||||
}
|
||||
|
||||
const verifier = genVerifier();
|
||||
const challenge = await genChallenge(verifier);
|
||||
const verifier = generateCodeVerifier();
|
||||
const challenge = await generateCodeChallenge(verifier);
|
||||
const state = crypto.randomUUID();
|
||||
const redirectUri = buildCallbackUrl();
|
||||
const scopeString = scopes?.filter((s) => s.trim()).join(" ");
|
||||
|
|
|
|||
18
ui/litellm-dashboard/src/utils/pkce.ts
Normal file
18
ui/litellm-dashboard/src/utils/pkce.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
const base64UrlEncode = (buffer: ArrayBuffer) => {
|
||||
const bytes = new Uint8Array(buffer);
|
||||
let binary = "";
|
||||
bytes.forEach((b) => (binary += String.fromCharCode(b)));
|
||||
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
||||
};
|
||||
|
||||
export const generateCodeVerifier = () => {
|
||||
const array = new Uint8Array(32);
|
||||
window.crypto.getRandomValues(array);
|
||||
return base64UrlEncode(array.buffer);
|
||||
};
|
||||
|
||||
export const generateCodeChallenge = async (verifier: string) => {
|
||||
const data = new TextEncoder().encode(verifier);
|
||||
const digest = await window.crypto.subtle.digest("SHA-256", data);
|
||||
return base64UrlEncode(digest);
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue