Can Reqwest handle HTTP authentication?

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.

Related Questions

Get Started Now

WebScraping.AI provides rotating proxies, Chromium rendering and built-in HTML parser for web scraping
Icon