refreshMcpOAuthToken function

Future<McpOAuthTokenGrant> refreshMcpOAuthToken(
  1. McpOAuthTokenGrant grant, {
  2. required McpOAuthClientAuthentication clientAuthentication,
  3. Iterable<String>? scopes,
  4. HttpClient? httpClient,
  5. Map<String, String> headers = const <String, String>{},
  6. Duration timeout = _defaultTokenTimeout,
  7. int maxResponseBytes = _defaultTokenResponseBytes,
  8. void onRequestOpened(
    1. HttpClientRequest request
    )?,
})

Refreshes a resource-bound MCP OAuth grant without mutating grant.

onRequestOpened observes the request before it is sent so an owning client can bind it to a larger lifecycle.

Implementation

Future<McpOAuthTokenGrant> refreshMcpOAuthToken(
  McpOAuthTokenGrant grant, {
  required McpOAuthClientAuthentication clientAuthentication,
  Iterable<String>? scopes,
  HttpClient? httpClient,
  Map<String, String> headers = const <String, String>{},
  Duration timeout = _defaultTokenTimeout,
  int maxResponseBytes = _defaultTokenResponseBytes,
  void Function(HttpClientRequest request)? onRequestOpened,
}) async {
  final authorizationServer = grant.authorizationServer;
  final endpoint = authorizationServer.tokenEndpoint;
  final refreshToken = grant.refreshToken;
  if (!_credentialValid(refreshToken)) {
    throw McpOAuthTokenException(
      'OAuth grant does not contain a usable refresh token.',
      endpoint: endpoint,
    );
  }
  final supportedGrants = authorizationServer.grantTypesSupported;
  if (supportedGrants != null &&
      !supportedGrants.contains(_refreshTokenGrant)) {
    throw McpOAuthTokenException(
      'Authorization server does not advertise refresh_token grants.',
      endpoint: endpoint,
    );
  }
  final requestedScopes = _validatedRefreshScopes(
    scopes,
    grant: grant,
    endpoint: endpoint,
  );
  _validateOAuthEndpointInputs(
    expectedClientId: grant.clientId,
    authorizationServer: authorizationServer,
    clientAuthentication: clientAuthentication,
    supportedMethods:
        authorizationServer.tokenEndpointAuthMethodsSupported ??
        const <String>[_clientSecretBasic],
    endpoint: endpoint,
    endpointLabel: 'OAuth token endpoint',
    headers: headers,
    timeout: timeout,
    maxResponseBytes: maxResponseBytes,
  );

  final response = await _postOAuthForm(
    endpoint: endpoint,
    form: <String, String>{
      'grant_type': _refreshTokenGrant,
      'refresh_token': refreshToken!,
      if (clientAuthentication.method != _clientSecretBasic)
        'client_id': clientAuthentication.clientId,
      'resource': grant.resource.toString(),
      if (scopes != null) 'scope': requestedScopes.join(' '),
      if (clientAuthentication.method == _clientSecretPost)
        'client_secret': clientAuthentication._clientSecret!,
    },
    clientAuthentication: clientAuthentication,
    httpClient: httpClient,
    headers: headers,
    timeout: timeout,
    maxResponseBytes: maxResponseBytes,
    endpointLabel: 'OAuth token endpoint',
    onRequestOpened: onRequestOpened,
  );
  return _parseTokenGrantResponse(
    statusCode: response.statusCode,
    mimeType: response.mimeType,
    body: _decodeOAuthResponse(response, endpoint, 'OAuth token endpoint'),
    endpoint: endpoint,
    resource: grant.resource,
    clientId: grant.clientId,
    authorizationServer: authorizationServer,
    effectiveScopes: requestedScopes,
    retainedRefreshToken: refreshToken,
    allowedResponseScopes: requestedScopes.toSet(),
  );
}