mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 19:05:11 +00:00
Use Web Crypto API for OAuth PKCE, remove Node.js crypto dependency
- Add pkce.ts with generatePKCE() using Web Crypto API - Update anthropic.ts, google-gemini-cli.ts, google-antigravity.ts - Replace Buffer.from() with atob() for base64 decoding - Works in both Node.js 20+ and browsers The OAuth modules still use Node.js http.createServer for callbacks, so they only work in CLI environments, but they no longer crash on import in browser bundles.
This commit is contained in:
parent
6a6d1a59f4
commit
c10fc1e081
4 changed files with 49 additions and 36 deletions
|
|
@ -2,25 +2,16 @@
|
|||
* Anthropic OAuth flow (Claude Pro/Max)
|
||||
*/
|
||||
|
||||
import { createHash, randomBytes } from "crypto";
|
||||
import { generatePKCE } from "./pkce.js";
|
||||
import type { OAuthCredentials } from "./types.js";
|
||||
|
||||
const decode = (s: string) => Buffer.from(s, "base64").toString();
|
||||
const decode = (s: string) => atob(s);
|
||||
const CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
|
||||
const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
||||
const TOKEN_URL = "https://console.anthropic.com/v1/oauth/token";
|
||||
const REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback";
|
||||
const SCOPES = "org:create_api_key user:profile user:inference";
|
||||
|
||||
/**
|
||||
* Generate PKCE code verifier and challenge
|
||||
*/
|
||||
function generatePKCE(): { verifier: string; challenge: string } {
|
||||
const verifier = randomBytes(32).toString("base64url");
|
||||
const challenge = createHash("sha256").update(verifier).digest("base64url");
|
||||
return { verifier, challenge };
|
||||
}
|
||||
|
||||
/**
|
||||
* Login with Anthropic OAuth (device code flow)
|
||||
*
|
||||
|
|
@ -31,7 +22,7 @@ export async function loginAnthropic(
|
|||
onAuthUrl: (url: string) => void,
|
||||
onPromptCode: () => Promise<string>,
|
||||
): Promise<OAuthCredentials> {
|
||||
const { verifier, challenge } = generatePKCE();
|
||||
const { verifier, challenge } = await generatePKCE();
|
||||
|
||||
// Build authorization URL
|
||||
const authParams = new URLSearchParams({
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
/**
|
||||
* Antigravity OAuth flow (Gemini 3, Claude, GPT-OSS via Google Cloud)
|
||||
* Uses different OAuth credentials than google-gemini-cli for access to additional models.
|
||||
*
|
||||
* NOTE: This module uses Node.js http.createServer for the OAuth callback.
|
||||
* It is only intended for CLI use, not browser environments.
|
||||
*/
|
||||
|
||||
import { createHash, randomBytes } from "crypto";
|
||||
import { createServer, type Server } from "http";
|
||||
import { generatePKCE } from "./pkce.js";
|
||||
import type { OAuthCredentials } from "./types.js";
|
||||
|
||||
// Antigravity OAuth credentials (different from Gemini CLI)
|
||||
const decode = (s: string) => Buffer.from(s, "base64").toString();
|
||||
const decode = (s: string) => atob(s);
|
||||
const CLIENT_ID = decode(
|
||||
"MTA3MTAwNjA2MDU5MS10bWhzc2luMmgyMWxjcmUyMzV2dG9sb2poNGc0MDNlcC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbQ==",
|
||||
);
|
||||
|
|
@ -30,15 +33,6 @@ const TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|||
// Fallback project ID when discovery fails
|
||||
const DEFAULT_PROJECT_ID = "rising-fact-p41fc";
|
||||
|
||||
/**
|
||||
* Generate PKCE code verifier and challenge
|
||||
*/
|
||||
function generatePKCE(): { verifier: string; challenge: string } {
|
||||
const verifier = randomBytes(32).toString("base64url");
|
||||
const challenge = createHash("sha256").update(verifier).digest("base64url");
|
||||
return { verifier, challenge };
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a local HTTP server to receive the OAuth callback
|
||||
*/
|
||||
|
|
@ -232,7 +226,7 @@ export async function loginAntigravity(
|
|||
onAuth: (info: { url: string; instructions?: string }) => void,
|
||||
onProgress?: (message: string) => void,
|
||||
): Promise<OAuthCredentials> {
|
||||
const { verifier, challenge } = generatePKCE();
|
||||
const { verifier, challenge } = await generatePKCE();
|
||||
|
||||
// Start local server for callback
|
||||
onProgress?.("Starting local server for OAuth callback...");
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
/**
|
||||
* Gemini CLI OAuth flow (Google Cloud Code Assist)
|
||||
* Standard Gemini models only (gemini-2.0-flash, gemini-2.5-*)
|
||||
*
|
||||
* NOTE: This module uses Node.js http.createServer for the OAuth callback.
|
||||
* It is only intended for CLI use, not browser environments.
|
||||
*/
|
||||
|
||||
import { createHash, randomBytes } from "crypto";
|
||||
import { createServer, type Server } from "http";
|
||||
import { generatePKCE } from "./pkce.js";
|
||||
import type { OAuthCredentials } from "./types.js";
|
||||
|
||||
const decode = (s: string) => Buffer.from(s, "base64").toString();
|
||||
const decode = (s: string) => atob(s);
|
||||
const CLIENT_ID = decode(
|
||||
"NjgxMjU1ODA5Mzk1LW9vOGZ0Mm9wcmRybnA5ZTNhcWY2YXYzaG1kaWIxMzVqLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29t",
|
||||
);
|
||||
|
|
@ -22,15 +25,6 @@ const AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|||
const TOKEN_URL = "https://oauth2.googleapis.com/token";
|
||||
const CODE_ASSIST_ENDPOINT = "https://cloudcode-pa.googleapis.com";
|
||||
|
||||
/**
|
||||
* Generate PKCE code verifier and challenge
|
||||
*/
|
||||
function generatePKCE(): { verifier: string; challenge: string } {
|
||||
const verifier = randomBytes(32).toString("base64url");
|
||||
const challenge = createHash("sha256").update(verifier).digest("base64url");
|
||||
return { verifier, challenge };
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a local HTTP server to receive the OAuth callback
|
||||
*/
|
||||
|
|
@ -263,7 +257,7 @@ export async function loginGeminiCli(
|
|||
onAuth: (info: { url: string; instructions?: string }) => void,
|
||||
onProgress?: (message: string) => void,
|
||||
): Promise<OAuthCredentials> {
|
||||
const { verifier, challenge } = generatePKCE();
|
||||
const { verifier, challenge } = await generatePKCE();
|
||||
|
||||
// Start local server for callback
|
||||
onProgress?.("Starting local server for OAuth callback...");
|
||||
|
|
|
|||
34
packages/ai/src/utils/oauth/pkce.ts
Normal file
34
packages/ai/src/utils/oauth/pkce.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* PKCE utilities using Web Crypto API.
|
||||
* Works in both Node.js 20+ and browsers.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encode bytes as base64url string.
|
||||
*/
|
||||
function base64urlEncode(bytes: Uint8Array): string {
|
||||
let binary = "";
|
||||
for (const byte of bytes) {
|
||||
binary += String.fromCharCode(byte);
|
||||
}
|
||||
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate PKCE code verifier and challenge.
|
||||
* Uses Web Crypto API for cross-platform compatibility.
|
||||
*/
|
||||
export async function generatePKCE(): Promise<{ verifier: string; challenge: string }> {
|
||||
// Generate random verifier
|
||||
const verifierBytes = new Uint8Array(32);
|
||||
crypto.getRandomValues(verifierBytes);
|
||||
const verifier = base64urlEncode(verifierBytes);
|
||||
|
||||
// Compute SHA-256 challenge
|
||||
const encoder = new TextEncoder();
|
||||
const data = encoder.encode(verifier);
|
||||
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
||||
const challenge = base64urlEncode(new Uint8Array(hashBuffer));
|
||||
|
||||
return { verifier, challenge };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue