use thiserror::Error;
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum SocialAuthError {
#[error("Network error: {0}")]
Network(String),
#[error("Invalid response: {0}")]
InvalidResponse(String),
#[error("Token validation failed: {0}")]
TokenValidation(String),
#[error("JWKS error: {0}")]
Jwks(String),
#[error("Discovery error: {0}")]
Discovery(String),
#[error("State validation failed: {0}")]
StateValidation(String),
#[error("PKCE validation failed: {0}")]
PkceValidation(String),
#[error("Provider error: {0}")]
Provider(String),
#[error("Configuration error: {0}")]
Configuration(String),
#[error("User mapping error: {0}")]
UserMapping(String),
#[error("Storage error: {0}")]
Storage(String),
#[error("Not supported: {0}")]
NotSupported(String),
#[error("Invalid state")]
InvalidState,
#[error("Token exchange error: {0}")]
TokenExchangeError(String),
#[error("Token refresh error: {0}")]
TokenRefreshError(String),
#[error("Invalid JWK: {0}")]
InvalidJwk(String),
#[error("Invalid ID token: {0}")]
InvalidIdToken(String),
#[error("UserInfo error: {0}")]
UserInfoError(String),
#[error("Invalid configuration: {0}")]
InvalidConfiguration(String),
#[error("Unknown error: {0}")]
Unknown(String),
#[error("Insecure endpoint: {0}")]
InsecureEndpoint(String),
}
impl From<reqwest::Error> for SocialAuthError {
fn from(error: reqwest::Error) -> Self {
SocialAuthError::Network(error.to_string())
}
}
impl From<serde_json::Error> for SocialAuthError {
fn from(error: serde_json::Error) -> Self {
SocialAuthError::InvalidResponse(error.to_string())
}
}
impl From<jsonwebtoken::errors::Error> for SocialAuthError {
fn from(error: jsonwebtoken::errors::Error) -> Self {
SocialAuthError::TokenValidation(error.to_string())
}
}
impl From<SocialAuthError> for crate::AuthenticationError {
fn from(error: SocialAuthError) -> Self {
match error {
SocialAuthError::Network(msg) => crate::AuthenticationError::Unknown(msg),
SocialAuthError::InvalidResponse(msg) => crate::AuthenticationError::Unknown(msg),
SocialAuthError::TokenValidation(_) => crate::AuthenticationError::InvalidToken,
SocialAuthError::StateValidation(_) => crate::AuthenticationError::InvalidToken,
_ => crate::AuthenticationError::Unknown(error.to_string()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let error = SocialAuthError::Network("Connection timeout".to_string());
assert_eq!(error.to_string(), "Network error: Connection timeout");
let error = SocialAuthError::TokenValidation("Invalid signature".to_string());
assert_eq!(
error.to_string(),
"Token validation failed: Invalid signature"
);
let error = SocialAuthError::Configuration("Missing client_id".to_string());
assert_eq!(error.to_string(), "Configuration error: Missing client_id");
}
#[test]
fn test_error_from_serde_json() {
let json_error = serde_json::from_str::<serde_json::Value>("{invalid json}").unwrap_err();
let social_error: SocialAuthError = json_error.into();
assert!(matches!(social_error, SocialAuthError::InvalidResponse(_)));
}
#[test]
fn test_error_to_authentication_error() {
let social_error = SocialAuthError::TokenValidation("Bad token".to_string());
let auth_error: crate::AuthenticationError = social_error.into();
assert!(matches!(
auth_error,
crate::AuthenticationError::InvalidToken
));
}
}