([])
const [loading, setLoading] = useState(false)
@@ -109,6 +111,28 @@ export const HuggingFace = ({ apiConfiguration, setApiConfigurationField }: Hugg
setApiConfigurationField,
])
+ // Start OAuth with PKCE
+ const handleStartOauth = useCallback(async () => {
+ try {
+ // Generate PKCE challenge using the library
+ const pkce = await pkceChallenge()
+ const state = crypto.randomUUID() // Use built-in UUID for state
+
+ // Store verifier/state in extension (secrets)
+ vscode.postMessage({
+ type: "storeHuggingFacePkce",
+ values: { verifier: pkce.code_verifier, state },
+ })
+
+ const authUrl = getHuggingFaceAuthUrl(uriScheme, pkce.code_challenge, state)
+
+ // Open externally via extension
+ vscode.postMessage({ type: "openExternal", url: authUrl })
+ } catch (e) {
+ console.error("Failed to start Hugging Face OAuth:", e)
+ }
+ }, [uriScheme])
+
const handleModelSelect = (modelId: string) => {
setApiConfigurationField("huggingFaceModelId", modelId)
// Reset provider selection when model changes
@@ -180,9 +204,9 @@ export const HuggingFace = ({ apiConfiguration, setApiConfigurationField }: Hugg
{!apiConfiguration?.huggingFaceApiKey && (
-
+
{t("settings:providers.getHuggingFaceApiKey")}
-
+
)}
diff --git a/webview-ui/src/oauth/urls.ts b/webview-ui/src/oauth/urls.ts
index 8abf0ca434..a3e4f6cfb9 100644
--- a/webview-ui/src/oauth/urls.ts
+++ b/webview-ui/src/oauth/urls.ts
@@ -1,4 +1,5 @@
import { Package } from "@roo/package"
+import { HUGGING_FACE_OAUTH_CLIENT_ID } from "../../../src/shared/oauth-constants"
export function getCallbackUrl(provider: string, uriScheme?: string) {
return encodeURIComponent(`${uriScheme || "vscode"}://${Package.publisher}.${Package.name}/${provider}`)
@@ -15,3 +16,21 @@ export function getOpenRouterAuthUrl(uriScheme?: string) {
export function getRequestyAuthUrl(uriScheme?: string) {
return `https://app.requesty.ai/oauth/authorize?callback_url=${getCallbackUrl("requesty", uriScheme)}`
}
+
+export function getHuggingFaceAuthUrl(uriScheme?: string, codeChallenge?: string, state?: string) {
+ const callback = getCallbackUrl("huggingface", uriScheme)
+ const scope = encodeURIComponent("openid profile inference-api")
+
+ let url = `https://huggingface.co/oauth/authorize?client_id=${HUGGING_FACE_OAUTH_CLIENT_ID}&redirect_uri=${callback}&response_type=code&scope=${scope}`
+
+ // Add PKCE parameters if provided
+ if (codeChallenge) {
+ url += `&code_challenge=${codeChallenge}&code_challenge_method=S256`
+ }
+
+ if (state) {
+ url += `&state=${encodeURIComponent(state)}`
+ }
+
+ return url
+}