arcly_http_identity/
error.rs1use arcly_http_core::web::error::{
6 BadRequest, Conflict, Forbidden, HttpException, Internal, NotFound, ServiceUnavailable,
7 TooManyRequests, Unauthorized,
8};
9
10#[derive(Debug, Clone)]
16pub enum IdentityError {
17 InvalidCredentials,
20 AccountLocked,
22 MfaRequired { challenge_id: String },
25 MfaFailed,
27 AlreadyExists,
29 InvalidToken,
32 Forbidden,
34 NotFound,
36 Internal(String),
38 Unavailable,
41 PasswordRejected(String),
44 ConsentRequired(Vec<String>),
46 RateLimited,
48}
49
50impl std::fmt::Display for IdentityError {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 match self {
53 Self::InvalidCredentials => write!(f, "invalid credentials"),
54 Self::AccountLocked => write!(f, "account locked"),
55 Self::MfaRequired { .. } => write!(f, "second factor required"),
56 Self::MfaFailed => write!(f, "second factor verification failed"),
57 Self::AlreadyExists => write!(f, "already exists"),
58 Self::InvalidToken => write!(f, "invalid or expired token"),
59 Self::Forbidden => write!(f, "forbidden"),
60 Self::NotFound => write!(f, "not found"),
61 Self::Internal(m) => write!(f, "internal error: {m}"),
62 Self::Unavailable => write!(f, "service unavailable"),
63 Self::PasswordRejected(m) => write!(f, "password rejected: {m}"),
64 Self::ConsentRequired(c) => write!(f, "consent required: {}", c.join(", ")),
65 Self::RateLimited => write!(f, "too many requests"),
66 }
67 }
68}
69
70impl std::error::Error for IdentityError {}
71
72impl From<IdentityError> for HttpException {
73 fn from(e: IdentityError) -> Self {
74 match e {
75 IdentityError::InvalidCredentials
78 | IdentityError::AccountLocked
79 | IdentityError::MfaFailed
80 | IdentityError::InvalidToken => Unauthorized::new("invalid credentials").into(),
81 IdentityError::MfaRequired { .. } => Unauthorized::new("second factor required").into(),
84 IdentityError::Forbidden => Forbidden::new("forbidden").into(),
85 IdentityError::NotFound => NotFound::new("not found").into(),
86 IdentityError::AlreadyExists => Conflict::new("already exists").into(),
87 IdentityError::Unavailable => ServiceUnavailable::new("service unavailable").into(),
88 IdentityError::Internal(m) => Internal::new(m).into(),
89 IdentityError::PasswordRejected(m) => BadRequest::new(m).into(),
91 IdentityError::ConsentRequired(c) => {
92 Forbidden::new(format!("consent required: {}", c.join(", "))).into()
93 }
94 IdentityError::RateLimited => {
95 TooManyRequests::new("too many requests — retry later").into()
96 }
97 }
98 }
99}
100
101pub type Result<T> = std::result::Result<T, IdentityError>;