runOpenRouterOAuthCliFlow function

Future<OpenRouterOAuthKey?> runOpenRouterOAuthCliFlow({
  1. required void onStatus(
    1. String
    ),
  2. Future<bool> openBrowserFn(
    1. String
    ) = openBrowser,
  3. Future<OpenRouterOAuthKey> exchangeFn({
    1. required String code,
    2. required String codeVerifier,
    3. String? label,
    }) = _defaultExchange,
  4. String keyLabel = openRouterDefaultKeyLabel,
  5. bool shouldOpenBrowserFn() = defaultBrowserLaunchPolicy,
  6. Duration timeout = const Duration(minutes: 5),
})

Runs the full automatic OAuth flow for the CLI: starts a localhost server, opens the browser, waits for the callback, and exchanges the code.

onStatus receives human-readable status lines ("authorization URL", "waiting", etc.). openBrowserFn, exchangeFn, shouldOpenBrowserFn and timeout are injectable for tests. The authorization URL is printed in every outcome (gh-1450); a false shouldOpenBrowserFn skips the launch entirely (the --no-browser flag / FA_NO_BROWSER env / headless auto-detect precedence resolves upstream).

Implementation

Future<OpenRouterOAuthKey?> runOpenRouterOAuthCliFlow({
  required void Function(String) onStatus,
  Future<bool> Function(String) openBrowserFn = openBrowser,
  Future<OpenRouterOAuthKey> Function({
        required String code,
        required String codeVerifier,
        String? label,
      })
      exchangeFn =
      _defaultExchange,
  String keyLabel = openRouterDefaultKeyLabel,
  bool Function() shouldOpenBrowserFn = defaultBrowserLaunchPolicy,
  Duration timeout = const Duration(minutes: 5),
}) async {
  final verifier = generateOpenRouterCodeVerifier();
  final challenge = generateOpenRouterCodeChallenge(verifier);
  final server = OpenRouterOAuthLocalCallbackServer();

  final callbackUrl = await server.start(timeout: timeout);
  onStatus('listening for OAuth callback on $callbackUrl');

  final authUrl = buildOpenRouterAuthUrl(
    codeChallenge: challenge,
    callbackUrl: callbackUrl,
    keyLabel: keyLabel,
  );

  await openAuthUrlWithStatus(
    url: authUrl.toString(),
    launchBrowser: shouldOpenBrowserFn(),
    openBrowserFn: openBrowserFn,
    onStatus: onStatus,
    openedMessage:
        'browser opened; complete authorization on the OpenRouter page',
  );

  final code = await server.waitForCode();
  if (code == null || code.isEmpty) {
    onStatus('no authorization code received (timeout or cancelled)');
    onStatus('$authorizationUrlPrefix$authUrl');
    return null;
  }
  onStatus('authorization code received, exchanging for API key...');

  try {
    final key = await exchangeFn(
      code: code,
      codeVerifier: verifier,
      label: keyLabel,
    );
    onStatus('OpenRouter authorized');
    return key;
  } on Exception catch (e) {
    onStatus('authorization failed: $e');
    return null;
  }
}