Yes, Reqwest, the most popular HTTP client library in Rust, provides comprehensive support for HTTP authentication. It handles multiple authentication methods including Basic Auth, Bearer tokens, and custom authentication headers.
Basic Authentication
HTTP Basic Authentication is supported through the convenient .basic_auth()
method:
use reqwest;
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let client = reqwest::Client::new();
// Basic auth with username and password
let response = client
.get("https://httpbin.org/basic-auth/user/pass")
.basic_auth("user", Some("pass"))
.send()
.await?;
println!("Status: {}", response.status());
println!("Response: {}", response.text().await?);
Ok(())
}
For username-only authentication (password is None
):
let response = client
.get("https://api.example.com/data")
.basic_auth("api_key", None)
.send()
.await?;
Bearer Token Authentication
Bearer authentication (commonly used with OAuth2 and API tokens) is handled by the .bearer_auth()
method:
use reqwest;
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let client = reqwest::Client::new();
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
let response = client
.get("https://api.github.com/user")
.bearer_auth(token)
.send()
.await?;
if response.status().is_success() {
let user_data: serde_json::Value = response.json().await?;
println!("User data: {:#}", user_data);
}
Ok(())
}
Custom Authentication Headers
For other authentication schemes, you can set custom headers:
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let client = reqwest::Client::new();
// Custom auth header
let response = client
.get("https://api.example.com/data")
.header(AUTHORIZATION, "Digest username=\"user\", realm=\"example\"")
.send()
.await?;
// Or using HeaderMap for multiple headers
let mut headers = HeaderMap::new();
headers.insert(AUTHORIZATION, HeaderValue::from_str("Custom token123")?);
headers.insert("X-API-Key", HeaderValue::from_str("your-api-key")?);
let response = client
.get("https://api.example.com/data")
.headers(headers)
.send()
.await?;
Ok(())
}
Client-Level Authentication
For APIs requiring authentication on every request, configure authentication at the client level:
use reqwest::{Client, header};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let mut headers = header::HeaderMap::new();
headers.insert(
header::AUTHORIZATION,
header::HeaderValue::from_str("Bearer your-token-here")?
);
let client = Client::builder()
.default_headers(headers)
.build()?;
// All requests will include the auth header
let response1 = client.get("https://api.example.com/users").send().await?;
let response2 = client.get("https://api.example.com/posts").send().await?;
Ok(())
}
Best Practices for Secure Authentication
1. Use Environment Variables
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let username = env::var("API_USERNAME")
.expect("API_USERNAME environment variable not set");
let password = env::var("API_PASSWORD")
.expect("API_PASSWORD environment variable not set");
let client = reqwest::Client::new();
let response = client
.get("https://api.example.com/secure")
.basic_auth(username, Some(password))
.send()
.await?;
Ok(())
}
2. Handle Authentication Errors
use reqwest::StatusCode;
match response.status() {
StatusCode::UNAUTHORIZED => {
eprintln!("Authentication failed: Invalid credentials");
return Err("Authentication error".into());
},
StatusCode::FORBIDDEN => {
eprintln!("Access denied: Insufficient permissions");
return Err("Authorization error".into());
},
status if status.is_success() => {
println!("Request successful!");
},
status => {
eprintln!("Request failed with status: {}", status);
}
}
3. Token Refresh Example
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
struct TokenResponse {
access_token: String,
expires_in: u64,
}
async fn get_auth_token(client: &reqwest::Client) -> Result<String, Box<dyn Error>> {
let response = client
.post("https://api.example.com/oauth/token")
.form(&[
("grant_type", "client_credentials"),
("client_id", &env::var("CLIENT_ID")?),
("client_secret", &env::var("CLIENT_SECRET")?),
])
.send()
.await?;
let token_data: TokenResponse = response.json().await?;
Ok(token_data.access_token)
}
Authentication with Cookies
Reqwest also supports cookie-based authentication:
use reqwest::cookie::Jar;
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let jar = Arc::new(Jar::default());
let client = reqwest::Client::builder()
.cookie_provider(jar.clone())
.build()?;
// Login to get session cookie
let login_response = client
.post("https://example.com/login")
.form(&[("username", "user"), ("password", "pass")])
.send()
.await?;
// Subsequent requests will include the session cookie
let protected_response = client
.get("https://example.com/protected")
.send()
.await?;
Ok(())
}
Reqwest's authentication support makes it easy to integrate with virtually any authenticated API or service while maintaining security best practices.