#!/usr/bin/env bun /**
- One-time script to obtain Claude OAuth tokens for clanky.
- Run: bun scripts/claude-oauth-login.ts
-
- Opens the authorize URL in your browser
-
- You log in / authorize
-
- Paste the code back here
-
- Tokens are saved to data/claude-oauth-tokens.json */
import { buildAuthorizeUrl, exchangeCodeForTokens } from "../src/llm/claudeOAuth.ts"; import { createInterface } from "node:readline";
const { url, verifier } = buildAuthorizeUrl();
console.log("
--- Claude OAuth Login ---
");
console.log("1. Open this URL in your browser:
");
console.log( ${url});
console.log("2. Log in with your Claude Pro/Max account and authorize.
");
console.log("3. You'll see an authorization code. Copy it and paste it below.
");
// Try to open the URL automatically try { const proc = Bun.spawn(["open", url], { stdout: "ignore", stderr: "ignore" }); await proc.exited; } catch { // ignore - user can open manually }
const rl = createInterface({ input: process.stdin, output: process.stdout }); const code = await new Promise((resolve) => { rl.question("Authorization code: ", (answer) => { rl.close(); resolve(answer.trim()); }); });
if (!code) { console.error(" No code provided. Aborting."); process.exit(1); }
try {
const tokens = await exchangeCodeForTokens(code, verifier);
console.log("
Tokens saved to data/claude-oauth-tokens.json");
console.log(Refresh token: ${tokens.refreshToken.slice(0, 12)}...);
console.log(Access token expires: ${new Date(tokens.expiresAt).toISOString()});
console.log("
You can now use provider: claude-oauth in your settings.");
console.log("Or set DEFAULT_PROVIDER=claude-oauth in your .env
");
} catch (error) {
console.error("
Failed to exchange code:", (error as Error).message);
process.exit(1);
}
