| Crates.io | reqwest-negotiate |
| lib.rs | reqwest-negotiate |
| version | 0.1.0 |
| created_at | 2026-01-01 23:27:12.136141+00 |
| updated_at | 2026-01-01 23:27:12.136141+00 |
| description | Kerberos/SPNEGO Negotiate authentication for reqwest |
| homepage | |
| repository | https://github.com/tom-lubenow/reqwest-negotiate |
| max_upload_size | |
| id | 2017700 |
| size | 93,785 |
Kerberos/SPNEGO Negotiate authentication for reqwest.
This crate provides an extension trait for reqwest::RequestBuilder that adds HTTP Negotiate (SPNEGO/Kerberos) authentication, similar to curl --negotiate.
| Platform | Status |
|---|---|
| Linux | Supported (MIT Kerberos) |
| macOS | Supported (Heimdal) |
| Windows | Not supported (contributions welcome) |
Windows would require SSPI integration instead of GSSAPI. Contributions are welcome.
Linux (Debian/Ubuntu):
sudo apt install libkrb5-dev
Linux (Fedora/RHEL):
sudo dnf install krb5-devel
macOS:
brew install krb5
You need a valid Kerberos ticket before making requests:
kinit user@REALM.COM
[dependencies]
reqwest-negotiate = "0.1"
reqwest = "0.13"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
use reqwest_negotiate::NegotiateAuthExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
let response = client
.get("https://api.example.com/protected")
.negotiate_auth()?
.send()
.await?;
println!("Status: {}", response.status());
Ok(())
}
For high-security environments, verify the server's identity:
use reqwest_negotiate::NegotiateAuthExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
let (builder, mut ctx) = client
.get("https://api.example.com/protected")
.negotiate_auth_mutual()?;
let response = builder.send().await?;
// Verify the server proved its identity
ctx.verify_response(&response)?;
println!("Status: {}", response.status());
Ok(())
}
If the service principal name differs from HTTP/<hostname>:
use reqwest_negotiate::NegotiateAuthExt;
let response = client
.get("https://api.example.com/protected")
.negotiate_auth_with_spn("HTTP/custom.principal@REALM.COM")?
.send()
.await?;
| Method | Returns | Description |
|---|---|---|
negotiate_auth() |
Result<RequestBuilder> |
Add Negotiate auth, SPN derived from URL |
negotiate_auth_with_spn(spn) |
Result<RequestBuilder> |
Add Negotiate auth with custom SPN |
negotiate_auth_mutual() |
Result<(RequestBuilder, NegotiateContext)> |
Add auth + return context for verification |
negotiate_auth_mutual_with_spn(spn) |
Result<(RequestBuilder, NegotiateContext)> |
Custom SPN + mutual auth |
| Method | Description |
|---|---|
verify_response(&response) |
Verify server's token from WWW-Authenticate header |
is_complete() |
Check if security context is fully established |
kinit)Authorization: Negotiate <token> headerWWW-AuthenticateThis crate aims to provide equivalent functionality to:
curl --negotiate -u : https://api.example.com/protected
Licensed under either of:
at your option.
Contributions are welcome! Areas of interest: