55 * It is only intended for CLI use, not browser environments.
66 */
77
8- import { parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime" ;
8+ import {
9+ parseOAuthAuthorizationInput ,
10+ resolveOAuthTokenExpiresAt ,
11+ resolveOAuthTokenLifetimeMs ,
12+ } from "openclaw/plugin-sdk/provider-oauth-runtime" ;
913import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime" ;
1014import { resolveCodexAuthIdentity } from "./openai-codex-auth-identity.js" ;
1115import {
@@ -113,46 +117,14 @@ function waitForManualPromptFallback(signal?: AbortSignal): Promise<null> {
113117 } ) ;
114118}
115119
116- function parseAuthorizationInput ( input : string ) : { code ?: string ; state ?: string } {
117- const value = input . trim ( ) ;
118- if ( ! value ) {
119- return { } ;
120- }
121-
122- try {
123- const url = new URL ( value ) ;
124- return {
125- code : url . searchParams . get ( "code" ) ?? undefined ,
126- state : url . searchParams . get ( "state" ) ?? undefined ,
127- } ;
128- } catch {
129- // not a URL
130- }
131-
132- if ( value . includes ( "#" ) ) {
133- const [ code , state ] = value . split ( "#" , 2 ) ;
134- return { code, state } ;
135- }
136-
137- if ( value . includes ( "code=" ) ) {
138- const params = new URLSearchParams ( value ) ;
139- return {
140- code : params . get ( "code" ) ?? undefined ,
141- state : params . get ( "state" ) ?? undefined ,
142- } ;
143- }
144-
145- return { code : value } ;
146- }
147-
148120async function promptForAuthorizationCode (
149121 onPrompt : ( prompt : OAuthPrompt ) => Promise < string > ,
150122 state : string ,
151123) : Promise < string | undefined > {
152124 const input = await onPrompt ( {
153125 message : "Paste the authorization code (or full redirect URL):" ,
154126 } ) ;
155- const parsed = parseAuthorizationInput ( input ) ;
127+ const parsed = parseOAuthAuthorizationInput ( input ) ;
156128 if ( parsed . state && parsed . state !== state ) {
157129 throw new Error ( "State mismatch" ) ;
158130 }
@@ -167,17 +139,12 @@ function formatMissingTokenResponseFields(json: TokenResponseJson): string {
167139 if ( ! json . refresh_token ) {
168140 missing . push ( "refresh_token" ) ;
169141 }
170- if ( parseStrictPositiveInteger ( json . expires_in ) === undefined ) {
142+ if ( resolveOAuthTokenLifetimeMs ( json . expires_in ) === undefined ) {
171143 missing . push ( "expires_in" ) ;
172144 }
173145 return missing . join ( ", " ) ;
174146}
175147
176- function resolveTokenExpiresAt ( expiresIn : unknown , nowMs = Date . now ( ) ) : number | undefined {
177- const seconds = parseStrictPositiveInteger ( expiresIn ) ;
178- return seconds === undefined ? undefined : nowMs + seconds * 1000 ;
179- }
180-
181148function formatTokenRequestError (
182149 operation : "exchange" | "refresh" ,
183150 error : unknown ,
@@ -259,7 +226,7 @@ async function exchangeAuthorizationCode(
259226
260227 const json = ( await response . json ( ) ) as TokenResponseJson ;
261228
262- const expires = resolveTokenExpiresAt ( json . expires_in ) ;
229+ const expires = resolveOAuthTokenExpiresAt ( json . expires_in ) ;
263230 if ( ! json . access_token || ! json . refresh_token || expires === undefined ) {
264231 return {
265232 type : "failed" ,
@@ -301,7 +268,7 @@ async function refreshAccessToken(
301268
302269 const json = ( await response . json ( ) ) as TokenResponseJson ;
303270
304- const expires = resolveTokenExpiresAt ( json . expires_in ) ;
271+ const expires = resolveOAuthTokenExpiresAt ( json . expires_in ) ;
305272 if ( ! json . access_token || ! json . refresh_token || expires === undefined ) {
306273 return {
307274 type : "failed" ,
@@ -502,7 +469,7 @@ export async function loginOpenAICodex(options: {
502469 code = result . code ;
503470 } else if ( manualCode ) {
504471 // Manual input won (or callback timed out and user had entered code)
505- const parsed = parseAuthorizationInput ( manualCode ) ;
472+ const parsed = parseOAuthAuthorizationInput ( manualCode ) ;
506473 if ( parsed . state && parsed . state !== state ) {
507474 throw new Error ( "State mismatch" ) ;
508475 }
@@ -516,7 +483,7 @@ export async function loginOpenAICodex(options: {
516483 throw manualError ;
517484 }
518485 if ( manualCode ) {
519- const parsed = parseAuthorizationInput ( manualCode ) ;
486+ const parsed = parseOAuthAuthorizationInput ( manualCode ) ;
520487 if ( parsed . state && parsed . state !== state ) {
521488 throw new Error ( "State mismatch" ) ;
522489 }
0 commit comments