systemprompt_api/routes/oauth/error/
conversions.rs1use systemprompt_config::SecretsBootstrapError;
8use systemprompt_identifiers::error::IdValidationError;
9use systemprompt_models::errors::GlobalConfigError;
10use systemprompt_oauth::{OauthError, OauthErrorKind};
11use systemprompt_oauth_issuance::IssuanceError;
12use systemprompt_traits::auth::AuthProviderError;
13
14use super::OAuthHttpError;
15use crate::routes::oauth::internal;
16
17impl From<GlobalConfigError> for OAuthHttpError {
18 fn from(err: GlobalConfigError) -> Self {
19 Self::server_error("Configuration unavailable").with_source(err)
20 }
21}
22
23impl From<IdValidationError> for OAuthHttpError {
24 fn from(err: IdValidationError) -> Self {
25 Self::invalid_request(err.to_string()).with_source(err)
26 }
27}
28
29impl From<OauthError> for OAuthHttpError {
30 fn from(err: OauthError) -> Self {
31 match err.kind() {
32 OauthErrorKind::InvalidClient => Self::invalid_client("Client authentication failed"),
33 OauthErrorKind::InvalidClientMetadata => Self::invalid_client_metadata(err.to_string()),
34 OauthErrorKind::InvalidGrant => Self::invalid_grant(err.to_string()),
35 OauthErrorKind::InvalidToken => Self::invalid_token(err.to_string()),
36 OauthErrorKind::InvalidRequest => Self::invalid_request(err.to_string()),
37 OauthErrorKind::AccessDenied => Self::access_denied(err.to_string()),
38 OauthErrorKind::UsernameUnavailable => Self::username_unavailable(
39 "Username is already taken. Please choose a different username.",
40 ),
41 OauthErrorKind::EmailExists => {
42 Self::email_exists("An account with this email already exists.")
43 },
44 OauthErrorKind::NotFound => Self::not_found(err.to_string()),
45 OauthErrorKind::ExpiredChallenge => Self::expired_challenge(
46 "The challenge has expired. Please start the ceremony again.",
47 ),
48 OauthErrorKind::InvalidCredential => Self::invalid_credential(
49 "WebAuthn verification failed. Please ensure your authenticator and browser are \
50 compatible.",
51 ),
52 OauthErrorKind::AuthenticationFailed => Self::authentication_failed(
53 "Authentication failed. Check the email address or register a passkey.",
54 ),
55 OauthErrorKind::ServerError => {
56 Self::server_error("Authorization operation failed").with_source(err)
57 },
58 }
59 }
60}
61
62impl From<AuthProviderError> for OAuthHttpError {
63 fn from(err: AuthProviderError) -> Self {
64 match err {
65 e @ (AuthProviderError::InvalidCredentials | AuthProviderError::InvalidToken) => {
66 Self::invalid_client(e.to_string())
67 },
68 e @ AuthProviderError::UserNotFound => Self::not_found(e.to_string()),
69 e @ AuthProviderError::TokenExpired => Self::invalid_grant(e.to_string()),
70 e @ AuthProviderError::InsufficientPermissions => Self::access_denied(e.to_string()),
71 other => Self::server_error("Authentication provider failed").with_source(other),
72 }
73 }
74}
75
76impl From<SecretsBootstrapError> for OAuthHttpError {
77 fn from(err: SecretsBootstrapError) -> Self {
78 Self::server_error("Secrets unavailable").with_source(err)
79 }
80}
81
82impl From<sqlx::Error> for OAuthHttpError {
83 fn from(err: sqlx::Error) -> Self {
84 Self::server_error("Database operation failed").with_source(err)
85 }
86}
87
88impl From<anyhow::Error> for OAuthHttpError {
89 fn from(err: anyhow::Error) -> Self {
90 Self::server_error("Authorization operation failed").with_source(err)
91 }
92}
93
94impl From<IssuanceError> for OAuthHttpError {
95 fn from(error: IssuanceError) -> Self {
96 match error {
97 IssuanceError::InvalidRequest { field, message } => {
98 Self::invalid_request(format!("{field}: {message}"))
99 },
100 IssuanceError::MalformedField {
101 field,
102 reason,
103 source,
104 } => internal::rejected(Self::invalid_request(format!("{field}: {reason}")), source),
105 IssuanceError::UnsupportedGrantType { grant_type } => {
106 Self::unsupported_grant_type(format!("Grant type '{grant_type}' is not supported"))
107 },
108 IssuanceError::InvalidClient => Self::invalid_client("Client authentication failed"),
109 IssuanceError::InvalidGrant { reason } => Self::invalid_grant(reason),
110 IssuanceError::RejectedGrant { reason, source } => {
111 internal::rejected(Self::invalid_grant(reason), source)
112 },
113 IssuanceError::InvalidRefreshToken { reason } => {
114 Self::invalid_grant(format!("Refresh token invalid: {reason}"))
115 },
116 IssuanceError::InvalidCredentials => Self::invalid_grant("Invalid credentials"),
117 IssuanceError::InvalidClientSecret => Self::invalid_client("Invalid client secret"),
118 IssuanceError::ExpiredCode => Self::invalid_grant("Authorization code expired"),
119 IssuanceError::ServerError { context, source } => {
120 internal::server_error(context, source)
121 },
122 IssuanceError::InvalidTarget { message } => Self::invalid_target(message),
123 IssuanceError::InvalidScope { message } => Self::invalid_scope(message),
124 IssuanceError::IdJagRejected(error) => Self::invalid_grant(error.to_string()),
125 IssuanceError::BoundResource(error) => Self::invalid_target(error.to_string()),
126 IssuanceError::Oauth(error) => Self::from(error),
127 }
128 }
129}