#http #auth #digest


Implementation of the Digest Auth algorithm as defined in IETF RFC 2069, 2617, and 7616, intended for HTTP clients

11 releases

0.3.1 May 9, 2023
0.3.0 May 25, 2021
0.2.4 Jan 23, 2021
0.2.3 Dec 6, 2019
0.1.2 Feb 27, 2019

#79 in Authentication

Download history 3121/week @ 2023-08-17 2516/week @ 2023-08-24 3337/week @ 2023-08-31 3256/week @ 2023-09-07 3558/week @ 2023-09-14 3950/week @ 2023-09-21 3923/week @ 2023-09-28 3014/week @ 2023-10-05 3941/week @ 2023-10-12 4308/week @ 2023-10-19 3812/week @ 2023-10-26 3917/week @ 2023-11-02 4005/week @ 2023-11-09 4859/week @ 2023-11-16 4137/week @ 2023-11-23 3480/week @ 2023-11-30

17,348 downloads per month
Used in 14 crates (7 directly)

MIT license

1.5K SLoC

Rust implementation of Digest Auth hashing algorithms, as defined in IETF RFC 2069, 2617, and 7616.

This crate provides the authentication header parsing and generation code.

Please see the docs and tests for examples.


This crate implements Digest Auth headers as specified by IETF RFCs 2069, 2617, and 7616. It can be used in conjunction with libraries like reqwest to access e.g. IP cameras that use this authentication scheme.

This library was written for the http client, but since the algorithm is symmetrical, it can be used by the server side as well. Server-side nonce management (generation, timed expiry) and authorization checking is left to user's implementation.

The AuthorizationHeader::digest() method can be used server-side to replicate the password/body hash; then just check if the computed digest matches what the user sent.


Basic usage:

use digest_auth::AuthContext;

// Value from the WWW-Authenticate HTTP header (usually in a HTTP 401 response)
let www_authenticate = r#"Digest realm="http-auth@example.org", qop="auth, auth-int", algorithm=MD5, nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS""#;

// Prepare an authorization context. Note that this is a GET request. There are different
// constructors available for POST or other request types. You can re-use it, but
// it's cheap to create a fresh one each time, as the struct uses references only.
let mut context = AuthContext::new("Mufasa", "Circle of Life", "/dir/index.html");
// For this test, we inject a custom cnonce. It's generated for you otherwise
// - you don't need `mut` in that case and needn't worry about this at all.

// Parse the prompt header. You can inspect the parsed object, its fields are public.
let mut prompt = digest_auth::parse(www_authenticate).unwrap();

// Compute a value for the Authorization header that we'll send back to the server
let answer = prompt.respond(&context).unwrap().to_string();
assert_eq!(answer, r#"Digest username="Mufasa", realm="http-auth@example.org", nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", uri="/dir/index.html", qop=auth, nc=00000001, cnonce="f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ", response="8ca523f5e9506fed4657c9700eebdbec", opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS", algorithm=MD5"#);

// The `prompt` variable is mutable, because the 'nc' counter (nonce reuse count)
// is inside the struct and updated automatically.

// You can re-use it for subsequent requests, assuming the server allows nonce re-use.
// Some poorly implemented servers will reject it and give you 401 again, in which case
// you should parse the new "WWW-Authenticate" header and use that instead.

let answer2 = prompt.respond(&context).unwrap().to_string();
// notice how the 'response' field changed - the 'nc' counter is included in the hash
assert_eq!(answer2, r#"Digest username="Mufasa", realm="http-auth@example.org", nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", uri="/dir/index.html", qop=auth, nc=00000002, cnonce="f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ", response="4b5d595ecf2db9df612ea5b45cd97101", opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS", algorithm=MD5"#);


~17K SLoC