44
55import crypto from 'crypto'
66import open from 'open'
7- import {
8- CLAUDE_OAUTH_CLIENT_ID ,
9- CLAUDE_OAUTH_AUTHORIZE_URL ,
10- CLAUDE_OAUTH_TOKEN_URL ,
11- } from '@codebuff/common/constants/claude-oauth'
7+ import { CLAUDE_OAUTH_CLIENT_ID } from '@codebuff/common/constants/claude-oauth'
128import {
139 saveClaudeOAuthCredentials ,
1410 clearClaudeOAuthCredentials ,
@@ -51,7 +47,7 @@ let pendingState: string | null = null
5147export function startOAuthFlow ( ) : { codeVerifier : string ; authUrl : string } {
5248 const codeVerifier = generateCodeVerifier ( )
5349 const codeChallenge = generateCodeChallenge ( codeVerifier )
54-
50+
5551 // Generate a random state parameter for CSRF protection
5652 const state = crypto . randomBytes ( 16 ) . toString ( 'hex' )
5753
@@ -65,8 +61,14 @@ export function startOAuthFlow(): { codeVerifier: string; authUrl: string } {
6561 authUrl . searchParams . set ( 'code' , 'true' )
6662 authUrl . searchParams . set ( 'client_id' , CLAUDE_OAUTH_CLIENT_ID )
6763 authUrl . searchParams . set ( 'response_type' , 'code' )
68- authUrl . searchParams . set ( 'redirect_uri' , 'https://console.anthropic.com/oauth/code/callback' )
69- authUrl . searchParams . set ( 'scope' , 'org:create_api_key user:profile user:inference' )
64+ authUrl . searchParams . set (
65+ 'redirect_uri' ,
66+ 'https://console.anthropic.com/oauth/code/callback' ,
67+ )
68+ authUrl . searchParams . set (
69+ 'scope' ,
70+ 'org:create_api_key user:profile user:inference' ,
71+ )
7072 authUrl . searchParams . set ( 'code_challenge' , codeChallenge )
7173 authUrl . searchParams . set ( 'code_challenge_method' , 'S256' )
7274 authUrl . searchParams . set ( 'state' , codeVerifier ) // opencode uses verifier as state
@@ -92,7 +94,9 @@ export async function exchangeCodeForTokens(
9294) : Promise < ClaudeOAuthCredentials > {
9395 const verifier = codeVerifier ?? pendingCodeVerifier
9496 if ( ! verifier ) {
95- throw new Error ( 'No code verifier found. Please start the OAuth flow again.' )
97+ throw new Error (
98+ 'No code verifier found. Please start the OAuth flow again.' ,
99+ )
96100 }
97101
98102 // The authorization code from claude.ai comes in format: code#state
@@ -140,55 +144,6 @@ export async function exchangeCodeForTokens(
140144 return credentials
141145}
142146
143- /**
144- * Refresh the access token using the refresh token.
145- */
146- export async function refreshAccessToken ( ) : Promise < ClaudeOAuthCredentials | null > {
147- const credentials = getClaudeOAuthCredentials ( )
148- if ( ! credentials ?. refreshToken ) {
149- return null
150- }
151-
152- try {
153- // Use the v1 OAuth token endpoint (same as opencode)
154- const response = await fetch ( 'https://console.anthropic.com/v1/oauth/token' , {
155- method : 'POST' ,
156- headers : {
157- 'Content-Type' : 'application/json' ,
158- } ,
159- body : JSON . stringify ( {
160- grant_type : 'refresh_token' ,
161- refresh_token : credentials . refreshToken ,
162- client_id : CLAUDE_OAUTH_CLIENT_ID ,
163- } ) ,
164- } )
165-
166- if ( ! response . ok ) {
167- // Refresh failed, clear credentials
168- clearClaudeOAuthCredentials ( )
169- return null
170- }
171-
172- const data = await response . json ( )
173-
174- const newCredentials : ClaudeOAuthCredentials = {
175- accessToken : data . access_token ,
176- refreshToken : data . refresh_token ?? credentials . refreshToken ,
177- expiresAt : Date . now ( ) + data . expires_in * 1000 ,
178- connectedAt : credentials . connectedAt ,
179- }
180-
181- // Save updated credentials
182- saveClaudeOAuthCredentials ( newCredentials )
183-
184- return newCredentials
185- } catch {
186- // Refresh failed, clear credentials
187- clearClaudeOAuthCredentials ( )
188- return null
189- }
190- }
191-
192147/**
193148 * Disconnect from Claude OAuth (clear credentials).
194149 */
0 commit comments