startOAuthFlow method

Future<OAuthTokens> startOAuthFlow({
  1. required Future<void> authURLHandler(
    1. String manualUrl, [
    2. String? automaticUrl
    ]),
  2. Future<void> openBrowser(
    1. String url
    )?,
  3. bool loginWithNeomageAi = false,
  4. bool inferenceOnly = false,
  5. int? expiresIn,
  6. String? orgUUID,
  7. String? loginHint,
  8. String? loginMethod,
  9. bool skipBrowserOpen = false,
})

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();
  }
}