startOAuthFlow method
Start the OAuth flow.
Implementation
Future<OAuthTokens> startOAuthFlow({
required Future<void> Function(String manualUrl, [String? automaticUrl])
authURLHandler,
Future<void> Function(String url)? openBrowser,
bool loginWithNeomageAi = false,
bool inferenceOnly = false,
int? expiresIn,
String? orgUUID,
String? loginHint,
String? loginMethod,
bool skipBrowserOpen = false,
}) async {
_authCodeListener = AuthCodeListener();
_port = await _authCodeListener!.start();
final codeChallenge = generateCodeChallenge(_codeVerifier);
final state = generateState();
final commonOpts = (
codeChallenge: codeChallenge,
state: state,
port: _port!,
loginWithNeomageAi: loginWithNeomageAi,
inferenceOnly: inferenceOnly,
orgUUID: orgUUID,
loginHint: loginHint,
loginMethod: loginMethod,
);
final manualFlowUrl = buildAuthUrl(
codeChallenge: commonOpts.codeChallenge,
state: commonOpts.state,
port: commonOpts.port,
isManual: true,
loginWithNeomageAi: commonOpts.loginWithNeomageAi,
inferenceOnly: commonOpts.inferenceOnly,
orgUUID: commonOpts.orgUUID,
loginHint: commonOpts.loginHint,
loginMethod: commonOpts.loginMethod,
);
final automaticFlowUrl = buildAuthUrl(
codeChallenge: commonOpts.codeChallenge,
state: commonOpts.state,
port: commonOpts.port,
isManual: false,
loginWithNeomageAi: commonOpts.loginWithNeomageAi,
inferenceOnly: commonOpts.inferenceOnly,
orgUUID: commonOpts.orgUUID,
loginHint: commonOpts.loginHint,
loginMethod: commonOpts.loginMethod,
);
// Wait for either automatic or manual auth code
final authorizationCode = await _waitForAuthorizationCode(state, () async {
if (skipBrowserOpen) {
await authURLHandler(manualFlowUrl, automaticFlowUrl);
} else {
await authURLHandler(manualFlowUrl);
if (openBrowser != null) await openBrowser(automaticFlowUrl);
}
});
final isAutomaticFlow = _authCodeListener?.hasPendingResponse ?? false;
try {
final tokenResponse = await exchangeCodeForTokens(
authorizationCode: authorizationCode,
state: state,
codeVerifier: _codeVerifier,
port: _port!,
useManualRedirect: !isAutomaticFlow,
expiresIn: expiresIn,
);
final profileInfo = await fetchProfileInfo(
accessToken: tokenResponse.accessToken,
);
if (isAutomaticFlow) {
final scopes = parseScopes(tokenResponse.scope);
_authCodeListener?.handleSuccessRedirect(scopes);
}
return _formatTokens(
tokenResponse,
profileInfo?.subscriptionType,
profileInfo?.rateLimitTier,
profileInfo?.rawProfile,
);
} catch (error) {
if (isAutomaticFlow) {
_authCodeListener?.handleErrorRedirect();
}
rethrow;
} finally {
_authCodeListener?.close();
}
}