Skip to main content

aster_forge_external_auth/
error.rs

1//! Error categories used by shared external authentication drivers.
2//!
3//! The variants describe where a failure belongs without prescribing an application's HTTP status
4//! code or response body. Application crates can preserve the category when converting this error
5//! into their own domain error type, which keeps call sites from repeating ad hoc string matching.
6
7/// Result type returned by external authentication helpers.
8pub type Result<T> = std::result::Result<T, ExternalAuthError>;
9
10/// Error returned by shared external authentication providers.
11#[derive(Debug, thiserror::Error)]
12pub enum ExternalAuthError {
13    /// Stored or submitted provider configuration is invalid.
14    #[error("{0}")]
15    Validation(String),
16    /// Runtime configuration is missing or unsupported.
17    #[error("{0}")]
18    Config(String),
19    /// The provider rejected credentials, returned an invalid token, or exposed invalid profile
20    /// data during an authentication flow.
21    #[error("{0}")]
22    InvalidCredentials(String),
23    /// Stored login-flow state is incomplete or corrupted.
24    #[error("{0}")]
25    State(String),
26    /// Internal client setup or infrastructure failed.
27    #[error("{0}")]
28    Internal(String),
29}
30
31impl ExternalAuthError {
32    /// Creates a validation error.
33    pub fn validation_error(message: impl Into<String>) -> Self {
34        Self::Validation(message.into())
35    }
36
37    /// Creates a configuration error.
38    pub fn config_error(message: impl Into<String>) -> Self {
39        Self::Config(message.into())
40    }
41
42    /// Creates an invalid-credentials error.
43    pub fn auth_invalid_credentials(message: impl Into<String>) -> Self {
44        Self::InvalidCredentials(message.into())
45    }
46
47    /// Creates a stored-state error.
48    pub fn state_error(message: impl Into<String>) -> Self {
49        Self::State(message.into())
50    }
51
52    /// Compatibility constructor for code moved from product crates where missing login-flow state
53    /// was reported through the database category.
54    pub fn database_operation(message: impl Into<String>) -> Self {
55        Self::State(message.into())
56    }
57
58    /// Creates an internal error.
59    pub fn internal_error(message: impl Into<String>) -> Self {
60        Self::Internal(message.into())
61    }
62}
63
64impl From<aster_forge_validation::ValidationError> for ExternalAuthError {
65    fn from(error: aster_forge_validation::ValidationError) -> Self {
66        Self::validation_error(error.to_string())
67    }
68}
69
70/// Extension trait for mapping lower-level errors into external auth errors with context.
71pub trait MapExternalAuthErr<T> {
72    /// Maps an error into [`ExternalAuthError`] by passing a context string to `error_fn`.
73    fn map_external_auth_err_ctx(
74        self,
75        context: impl Into<String>,
76        error_fn: fn(String) -> ExternalAuthError,
77    ) -> Result<T>;
78}
79
80impl<T, E> MapExternalAuthErr<T> for std::result::Result<T, E>
81where
82    E: std::fmt::Display,
83{
84    fn map_external_auth_err_ctx(
85        self,
86        context: impl Into<String>,
87        error_fn: fn(String) -> ExternalAuthError,
88    ) -> Result<T> {
89        let context = context.into();
90        self.map_err(|error| error_fn(format!("{context}: {error}")))
91    }
92}