refreshOAuthToken function

Future<OAuthTokens> refreshOAuthToken({
  1. required String refreshToken,
  2. List<String>? requestedScopes,
  3. HttpClient? httpClient,
})

Refresh an OAuth token.

Implementation

Future<OAuthTokens> refreshOAuthToken({
  required String refreshToken,
  List<String>? requestedScopes,
  HttpClient? httpClient,
}) async {
  final config = getOauthConfig();
  final body = {
    'grant_type': 'refresh_token',
    'refresh_token': refreshToken,
    'client_id': config.clientId,
    'scope':
        (requestedScopes?.isNotEmpty == true
                ? requestedScopes!
                : neomageAiOAuthScopes)
            .join(' '),
  };

  final client = httpClient ?? HttpClient();
  try {
    final request = await client.postUrl(Uri.parse(config.tokenUrl));
    request.headers.contentType = ContentType.json;
    request.write(jsonEncode(body));
    final response = await request.close().timeout(const Duration(seconds: 15));

    final responseBody = await response.transform(utf8.decoder).join();

    if (response.statusCode != 200) {
      throw Exception('Token refresh failed: $responseBody');
    }

    final data = OAuthTokenExchangeResponse.fromJson(
      jsonDecode(responseBody) as Map<String, dynamic>,
    );

    final expiresAt =
        DateTime.now().millisecondsSinceEpoch + data.expiresIn * 1000;
    final scopes = parseScopes(data.scope);

    return OAuthTokens(
      accessToken: data.accessToken,
      refreshToken: data.refreshToken,
      expiresAt: expiresAt,
      scopes: scopes,
      tokenAccount: data.account != null
          ? OAuthTokenAccountInfo(
              uuid: data.account!.uuid,
              emailAddress: data.account!.emailAddress,
              organizationUuid: data.organization?.uuid,
            )
          : null,
    );
  } finally {
    if (httpClient == null) client.close();
  }
}