My Quick Notes

Ain't Nobody Got Time to Read

January 13, 2026

Implement basic authentication in actix-web

This will do:

  • If both username/password are empty, does not require to enter username/password when access the website.
  • If any of username/password are not empty, require user to enter username/password to access the website.

Assume username/password are stored in a struct named Config.

#[derive(Clone)]
struct Config {
    basic_auth_user: String,
    basic_auth_pass: String,
}

Create a function to validate the entered username/password:

async fn basic_auth_validator(
    req: ServiceRequest,
    credentials: BasicAuth,
) -> Result<ServiceRequest, (Error, ServiceRequest)> {
    let mut user_ok = false;
    let mut pass_ok = false;
    if let Some(config) = req.app_data::<Data<Config>>() {
        user_ok =
            config.basic_auth_user.is_empty() || credentials.user_id() == config.basic_auth_user;
        pass_ok = config.basic_auth_pass.is_empty()
            || credentials.password() == Some(config.basic_auth_pass.as_str());
    }
    if user_ok && pass_ok {
        Ok(req)
    } else {
        let resp = HttpResponse::Unauthorized()
            .insert_header((header::WWW_AUTHENTICATE, r#"Basic realm="Restricted""#))
            .finish();
        let err = InternalError::from_response("Unauthorized", resp).into();
        Err((err, req))
    }
}

Add the validator to actix App:

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    // Config should be parsed from config file or from database
    let config = Config {
        basic_auth_user: "admin".to_string(),
        basic_auth_pass: "admin".to_string(),
    };
    let config_data = Arc::new(config.clone());

    HttpServer::new(move || {
        // If username/password are empty, do not enable basic auth
        let enable_basic_auth =
            !config.basic_auth_user.is_empty() || !config.basic_auth_pass.is_empty();

        App::new()
            .wrap(Condition::new(
                enable_basic_auth,
                HttpAuthentication::basic(basic_auth_validator),
            ))
            .app_data(Data::from(config_data.clone()))
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}
PreviousSetup local agent on Raspberry Pi 5 with OpenClaw and Ollama
NextGit - Sign your commit with GPG key

Comments