use base64::{Engine, engine::general_purpose::STANDARD};
#[derive(Clone)]
pub enum Auth {
ApiKey(String),
Token(String),
}
impl Auth {
pub fn api_key(key: impl Into<String>) -> Self {
Auth::ApiKey(key.into())
}
pub fn token(token: impl Into<String>) -> Self {
Auth::Token(token.into())
}
pub(crate) fn header_value(&self) -> String {
match self {
Auth::ApiKey(k) => format!("Basic {}", STANDARD.encode(k.as_bytes())),
Auth::Token(t) => format!("Bearer {t}"),
}
}
}
impl std::fmt::Debug for Auth {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Auth::ApiKey(_) => f.write_str("Auth::ApiKey(<redacted>)"),
Auth::Token(_) => f.write_str("Auth::Token(<redacted>)"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn api_key_becomes_basic_header() {
let a = Auth::api_key("app.key:secret");
assert_eq!(a.header_value(), "Basic YXBwLmtleTpzZWNyZXQ=");
}
#[test]
fn token_becomes_bearer_header() {
assert_eq!(Auth::token("tok123").header_value(), "Bearer tok123");
}
#[test]
fn debug_redacts_credentials() {
let dbg = format!("{:?}", Auth::api_key("app.key:secret"));
assert!(!dbg.contains("secret"));
let dbg = format!("{:?}", Auth::token("tok123"));
assert!(!dbg.contains("tok123"));
}
}