ZetCode

Dart HttpClientDigestCredentials

last modified October 18, 2026

The HttpClientDigestCredentials class in Dart provides support for HTTP digest authentication. It's part of Dart's dart:io library.

Digest authentication is more secure than basic authentication as it doesn't send passwords in clear text. It uses a challenge-response mechanism.

Basic Definition

HttpClientDigestCredentials handles the digest authentication protocol. It stores username and password for generating proper responses.

Key features include automatic challenge handling, nonce management, and proper header generation. It works with Dart's HttpClient class.

Basic Digest Authentication

This example shows basic usage of HttpClientDigestCredentials.

main.dart
import 'dart:io';

void main() async {
  var client = HttpClient();
  var url = Uri.parse('https://httpbin.org/digest-auth/auth/user/password');
  var credentials = HttpClientDigestCredentials('user', 'password');
  
  client.addCredentials(
    url,
    'me@kennethreitz.com',
    credentials
  );
  
  try {
    var request = await client.getUrl(url);
    var response = await request.close();
    await response.drain<void>();
    print('Status: ${response.statusCode}');
  } finally {
    client.close();
  }
}

We create HttpClientDigestCredentials with username and password. The credentials are added to the client for a specific URI and realm. The realm must match the realm sent by the server in its authentication challenge.

$ dart main.dart
Status: 200

Handling Multiple Requests

This example shows how credentials work across multiple requests.

main.dart
import 'dart:io';

void main() async {
  var client = HttpClient();
  var url = Uri.parse('https://httpbin.org/digest-auth/auth/user/password');
  var credentials = HttpClientDigestCredentials('user', 'password');
  
  client.addCredentials(
    url,
    'me@kennethreitz.com',
    credentials
  );
  
  for (var i = 0; i < 3; i++) {
    try {
      var request = await client.getUrl(url);
      var response = await request.close();
      await response.drain<void>();
      print('Request ${i+1}: ${response.statusCode}');
    } catch (e) {
      print('Error: $e');
    }
  }
  
  client.close();
}

The same credentials are reused for multiple requests to the same realm. The client handles the authentication flow automatically.

$ dart main.dart
Request 1: 200
Request 2: 200
Request 3: 200

Handling Authentication Failure

This example demonstrates handling invalid credentials.

main.dart
import 'dart:io';

void main() async {
  var client = HttpClient();
  var url = Uri.parse('https://httpbin.org/digest-auth/auth/user/password');
  var credentials = HttpClientDigestCredentials('wrong', 'credentials');
  
  client.addCredentials(
    url,
    'me@kennethreitz.com',
    credentials
  );
  
  try {
    var request = await client.getUrl(url);
    var response = await request.close();
    await response.drain<void>();
    
    if (response.statusCode == HttpStatus.unauthorized) {
      print('Authentication failed: ${response.statusCode}');
    } else {
      print('Status: ${response.statusCode}');
    }
  } finally {
    client.close();
  }
}

When credentials are invalid, the server responds with 401 Unauthorized. We check the status code instead of expecting an exception.

$ dart main.dart
Authentication failed: 401

Matching the Authentication Realm

This example shows how to use the realm expected by the server.

main.dart
import 'dart:io';

void main() async {
  var client = HttpClient();
  var url = Uri.parse('https://httpbin.org/digest-auth/auth/admin/secret');
  var credentials = HttpClientDigestCredentials('admin', 'secret');
  
  // The realm is part of the digest hash, so it must match the server.
  client.addCredentials(
    url,
    'me@kennethreitz.com',
    credentials
  );
  
  try {
    var request = await client.getUrl(url);
    var response = await request.close();
    await response.drain<void>();
    print('Status: ${response.statusCode}');
  } finally {
    client.close();
  }
}

The realm parameter is used when computing the digest response, so it must match the realm sent by the server. The URL selects the protected resource; different paths can require different credentials.

$ dart main.dart
Status: 200

Using with HttpClientRequest

This example shows how credentials registered on the client apply to a request created with HttpClientRequest.

main.dart
import 'dart:io';

void main() async {
  var client = HttpClient();
  var url = Uri.parse('https://httpbin.org/digest-auth/auth/user/password');
  var credentials = HttpClientDigestCredentials('user', 'password');
  client.addCredentials(url, 'me@kennethreitz.com', credentials);
  
  try {
    var request = await client.getUrl(url);
    var response = await request.close();
    await response.drain<void>();
    print('Status: ${response.statusCode}');
  } finally {
    client.close();
  }
}

Digest headers cannot be computed until the server supplies a nonce, so credentials are registered on the client. The client handles the challenge and retries the request with the generated Authorization header.

$ dart main.dart
Status: 200

Best Practices

Source

Dart HttpClientDigestCredentials Documentation

This tutorial covered Dart's HttpClientDigestCredentials class with practical examples showing basic usage, error handling, and advanced configuration.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Dart tutorials.