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 ///
74 /// # Errors
75 ///
76 /// Returns [`ExternalAuthError`] after mapping any source error produced by the callback.
77 fn map_external_auth_err_ctx(
78 self,
79 context: impl Into<String>,
80 error_fn: fn(String) -> ExternalAuthError,
81 ) -> Result<T>;
82}
83
84impl<T, E> MapExternalAuthErr<T> for std::result::Result<T, E>
85where
86 E: std::fmt::Display,
87{
88 fn map_external_auth_err_ctx(
89 self,
90 context: impl Into<String>,
91 error_fn: fn(String) -> ExternalAuthError,
92 ) -> Result<T> {
93 let context = context.into();
94 self.map_err(|error| error_fn(format!("{context}: {error}")))
95 }
96}