runChatGptOAuthCliFlow function
Future<ChatGptOAuthCredentials?>
runChatGptOAuthCliFlow({})
Runs the interactive ChatGPT OAuth sign-in: binds the local callback server, opens the authorize URL, and exchanges the callback code.
ports forwards to ChatGptOAuthLocalCallbackServer.start — the
loopback candidates tried in order; the first successful bind serves
the callback. The authorization URL is printed in every outcome
(gh-1450); a false shouldOpenBrowserFn skips the launch (the
--no-browser flag / FA_NO_BROWSER env / headless auto-detect
precedence resolves upstream).
Implementation
Future<ChatGptOAuthCredentials?> runChatGptOAuthCliFlow({
required void Function(String) onStatus,
Future<bool> Function(String) openBrowserFn = openBrowser,
Future<ChatGptOAuthCredentials> Function({
required String code,
required String redirectUri,
required String verifier,
})
exchangeFn =
_defaultExchange,
Duration timeout = const Duration(minutes: 5),
List<int> ports = const [1455, 1457],
bool Function() shouldOpenBrowserFn = defaultBrowserLaunchPolicy,
}) async {
final server = ChatGptOAuthLocalCallbackServer();
final verifier = generateChatGptPkceVerifier();
final state = generateChatGptState();
final redirectUri = await server.start(timeout: timeout, ports: ports);
final authUrl = buildChatGptAuthorizeUrl(
redirectUri: redirectUri,
codeChallenge: generateChatGptPkceChallenge(verifier),
state: state,
);
onStatus('listening for ChatGPT OAuth callback on $redirectUri');
await openAuthUrlWithStatus(
url: authUrl.toString(),
launchBrowser: shouldOpenBrowserFn(),
openBrowserFn: openBrowserFn,
onStatus: onStatus,
openedMessage: 'browser opened; complete authorization with ChatGPT',
);
final callback = await server.waitForCallback();
if (callback == null) {
onStatus('no authorization callback received (timeout or cancelled)');
onStatus('$authorizationUrlPrefix$authUrl');
return null;
}
if (callback.error != null) {
onStatus(
'ChatGPT authorization failed: ${callback.errorDescription ?? callback.error}',
);
return null;
}
if (callback.state != state ||
callback.code == null ||
callback.code!.isEmpty) {
onStatus('ChatGPT authorization callback was invalid');
return null;
}
try {
final credentials = await exchangeFn(
code: callback.code!,
redirectUri: redirectUri,
verifier: verifier,
);
onStatus('ChatGPT authorized');
return credentials;
} on Object catch (error) {
onStatus('ChatGPT authorization failed: $error');
return null;
}
}