anchor.diff:      // to given serverBaseUrl. Otherwise credential leaks might ocurr when
       // archive_url hosted on 3rd party server that should not receive
       // credentials of the first party.
  -    if (credential.canAuthenticate(request.url.toString())) {
  +    if (credential != null &&
  +        credential.canAuthenticate(request.url.toString())) {
         request.headers[HttpHeaders.authorizationHeader] =
             await credential.getAuthorizationHeaderValue();
       }
  -    return _inner.send(request);
  +
  +    try {
  +      final response = await _inner.send(request);
  +      if (response.statusCode == 401) {
  +        _throwAuthException(response);
  +      }
  +      return response;
  +    } on PubHttpException catch (e) {
  +      if (e.response?.statusCode == 403) {
  +        _throwAuthException(e.response);
  +      }
  +      rethrow;
  +    }
  +  }
  +
  +  /// Throws [AuthenticationException] that includes response status code and
  +  /// message parsed from WWW-Authenticate header usign
  +  /// [RFC 7235 section 4.1][RFC] specifications.
  +  ///
  +  /// [RFC]: https://datatracker.ietf.org/doc/html/rfc7235#section-4.1
  +  void _throwAuthException(http.BaseResponse response) {
  +    String serverMessage;
  +    if (response.headers.containsKey(HttpHeaders.wwwAuthenticateHeader)) {
  +      try {
  +        final header = response.headers[HttpHeaders.wwwAuthenticateHeader];
  +        final challenge = AuthenticationChallenge.parseHeader(header)
  +            .firstWhereOrNull((challenge) =>
  +                challenge.scheme == 'bearer' &&
  +                challenge.parameters['realm'] == 'pub' &&
  +                challenge.parameters['message'] != null);
  +        serverMessage = challenge?.parameters['message'];
  +      } on FormatException {
  +        // Ignore errors might be caused when parsing invalid header values
  +      }
  +    }
  +    if (serverMessage != null) {
  +      // Only allow printable ASCII, map anything else to whitespace, take
  +      // at-most 1024 characters.
  +      serverMessage = String.fromCharCodes(serverMessage.runes
  +          .map((r) => 32 <= r && r <= 127 ? r : 32)
  +          .take(1024));
  +    }
  +    throw AuthenticationException(response.statusCode, serverMessage);
     }
   
     @override
     void close() => _inner.close();
  +}
  +
  +/// Token authenticated related exception.
  +class AuthenticationException implements Exception {
  +  const AuthenticationException(this.statusCode, this.serverMessage);
  +
  +  final int statusCode;
  +  final String serverMessage;
  +
  +  @override
  +  String toString() {
  +    var message = 'Authentication error ($statusCode)';
  +    if (serverMessage != null) {
  +      message += ': $serverMessage';
  +    }
  +    return message;
  +  }
   }
   
   /// Invoke [fn] with a [http.Client] capable of authenticating against
  
positive.code: 
  import 'dart:io';
  
  import 'package:http/http.dart' as http;
  
  import '../http.dart';
  import '../log.dart' as log;
  import '../system_cache.dart';
  
negative.code:   Future<T> Function(http.Client) fn,
  ) async {
    final credential = systemCache.tokenStore.findCredential(hostedUrl);
    final http.Client client = _AuthenticatedClient(httpClient, credential);
  
    try {
      return await fn(client);
    } on AuthenticationException catch (error) {
      String message;
  
      if (error.statusCode == 401) {
        if (systemCache.tokenStore.removeCredential(hostedUrl)) {
          log.warning('Invalid token for $hostedUrl deleted.');
        }
        message = '$hostedUrl package repository requested authentication! '
            'You can provide credential using:\n'
            '    pub token add $hostedUrl';
      }
      if (error.statusCode == 403) {
        message = 'Insufficient permissions to the resource in $hostedUrl '
            'package repository. You can modify credential using:\n'
            '    pub token add $hostedUrl';
      }
  
      if (error.serverMessage?.isNotEmpty == true) {
        message += '\n${error.serverMessage}';
      }
  
      throw DataException(message);
    }
  }
  