mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-14 02:22:54 +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:
@@ -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(" ");
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
Reference in New Issue
Block a user