runChatGptOAuthCliFlow function
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),
}) async {
final server = ChatGptOAuthLocalCallbackServer();
final verifier = generateChatGptPkceVerifier();
final state = generateChatGptState();
final redirectUri = await server.start(timeout: timeout);
final authUrl = buildChatGptAuthorizeUrl(
redirectUri: redirectUri,
codeChallenge: generateChatGptPkceChallenge(verifier),
state: state,
);
onStatus('listening for ChatGPT OAuth callback on $redirectUri');
if (await openBrowserFn(authUrl.toString())) {
onStatus('browser opened; complete authorization with ChatGPT');
} else {
onStatus('could not open browser automatically');
onStatus('open this URL manually: $authUrl');
}
final callback = await server.waitForCallback();
if (callback == null) {
onStatus('no authorization callback received (timeout or cancelled)');
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;
}
}