axum_gate/authn/
errors.rs1use crate::errors::{ErrorSeverity, UserFriendlyError};
35
36use thiserror::Error;
37
38#[derive(Debug, thiserror::Error)]
41#[non_exhaustive]
42pub enum AuthenticationError {
43 #[error("Invalid credentials provided")]
45 InvalidCredentials,
46}
47
48#[derive(Debug, Error)]
53#[non_exhaustive]
54pub enum AuthnError {
55 #[error("Authentication error: {error}")]
57 Authentication {
58 #[source]
60 error: AuthenticationError,
61 context: Option<String>,
63 },
64}
65
66impl AuthnError {
67 pub fn from_authentication(error: AuthenticationError, context: Option<String>) -> Self {
69 AuthnError::Authentication { error, context }
70 }
71
72 pub fn invalid_credentials(context: Option<String>) -> Self {
74 Self::from_authentication(AuthenticationError::InvalidCredentials, context)
75 }
76
77 fn support_code_inner(&self) -> String {
78 match self {
79 AuthnError::Authentication { error, .. } => match error {
80 AuthenticationError::InvalidCredentials => "AUTHN-INVALID-CREDS".to_string(),
81 },
82 }
83 }
84}
85
86impl UserFriendlyError for AuthnError {
87 fn user_message(&self) -> String {
88 match self {
89 AuthnError::Authentication { error, .. } => match error {
90 AuthenticationError::InvalidCredentials => {
91 "The username or password you entered is incorrect. Please check your credentials and try again.".to_string()
92 }
93 },
94 }
95 }
96
97 fn developer_message(&self) -> String {
98 match self {
99 AuthnError::Authentication { error, context } => {
100 let context_info = context
101 .as_ref()
102 .map(|c| format!(" Context: {}", c))
103 .unwrap_or_default();
104 format!("Authentication failure: {}.{}", error, context_info)
105 }
106 }
107 }
108
109 fn support_code(&self) -> String {
110 self.support_code_inner()
111 }
112
113 fn severity(&self) -> ErrorSeverity {
114 match self {
115 AuthnError::Authentication { error, .. } => match error {
116 AuthenticationError::InvalidCredentials => ErrorSeverity::Warning,
117 },
118 }
119 }
120
121 fn suggested_actions(&self) -> Vec<String> {
122 match self {
123 AuthnError::Authentication { error, .. } => match error {
124 AuthenticationError::InvalidCredentials => vec![
125 "Double-check your username and password for typos".to_string(),
126 "Ensure Caps Lock is not accidentally enabled".to_string(),
127 "Use the 'Forgot Password' link if you can't remember your password"
128 .to_string(),
129 "Contact support if you're sure your credentials are correct".to_string(),
130 ],
131 },
132 }
133 }
134
135 fn is_retryable(&self) -> bool {
136 match self {
137 AuthnError::Authentication { error, .. } => match error {
138 AuthenticationError::InvalidCredentials => true,
139 },
140 }
141 }
142}