use systemprompt_config::SecretsBootstrapError;
use systemprompt_identifiers::error::IdValidationError;
use systemprompt_models::errors::GlobalConfigError;
use systemprompt_oauth::{OauthError, OauthErrorKind};
use systemprompt_oauth_issuance::IssuanceError;
use systemprompt_traits::auth::AuthProviderError;
use super::OAuthHttpError;
use crate::routes::oauth::internal;
impl From<GlobalConfigError> for OAuthHttpError {
fn from(err: GlobalConfigError) -> Self {
Self::server_error("Configuration unavailable").with_source(err)
}
}
impl From<IdValidationError> for OAuthHttpError {
fn from(err: IdValidationError) -> Self {
Self::invalid_request(err.to_string()).with_source(err)
}
}
impl From<OauthError> for OAuthHttpError {
fn from(err: OauthError) -> Self {
match err.kind() {
OauthErrorKind::InvalidClient => Self::invalid_client("Client authentication failed"),
OauthErrorKind::InvalidClientMetadata => Self::invalid_client_metadata(err.to_string()),
OauthErrorKind::InvalidGrant => Self::invalid_grant(err.to_string()),
OauthErrorKind::InvalidToken => Self::invalid_token(err.to_string()),
OauthErrorKind::InvalidRequest => Self::invalid_request(err.to_string()),
OauthErrorKind::AccessDenied => Self::access_denied(err.to_string()),
OauthErrorKind::UsernameUnavailable => Self::username_unavailable(
"Username is already taken. Please choose a different username.",
),
OauthErrorKind::EmailExists => {
Self::email_exists("An account with this email already exists.")
},
OauthErrorKind::NotFound => Self::not_found(err.to_string()),
OauthErrorKind::ExpiredChallenge => Self::expired_challenge(
"The challenge has expired. Please start the ceremony again.",
),
OauthErrorKind::InvalidCredential => Self::invalid_credential(
"WebAuthn verification failed. Please ensure your authenticator and browser are \
compatible.",
),
OauthErrorKind::AuthenticationFailed => Self::authentication_failed(
"Authentication failed. Check the email address or register a passkey.",
),
OauthErrorKind::ServerError => {
Self::server_error("Authorization operation failed").with_source(err)
},
}
}
}
impl From<AuthProviderError> for OAuthHttpError {
fn from(err: AuthProviderError) -> Self {
match err {
e @ (AuthProviderError::InvalidCredentials | AuthProviderError::InvalidToken) => {
Self::invalid_client(e.to_string())
},
e @ AuthProviderError::UserNotFound => Self::not_found(e.to_string()),
e @ AuthProviderError::TokenExpired => Self::invalid_grant(e.to_string()),
e @ AuthProviderError::InsufficientPermissions => Self::access_denied(e.to_string()),
other => Self::server_error("Authentication provider failed").with_source(other),
}
}
}
impl From<SecretsBootstrapError> for OAuthHttpError {
fn from(err: SecretsBootstrapError) -> Self {
Self::server_error("Secrets unavailable").with_source(err)
}
}
impl From<sqlx::Error> for OAuthHttpError {
fn from(err: sqlx::Error) -> Self {
Self::server_error("Database operation failed").with_source(err)
}
}
impl From<anyhow::Error> for OAuthHttpError {
fn from(err: anyhow::Error) -> Self {
Self::server_error("Authorization operation failed").with_source(err)
}
}
impl From<IssuanceError> for OAuthHttpError {
fn from(error: IssuanceError) -> Self {
match error {
IssuanceError::InvalidRequest { field, message } => {
Self::invalid_request(format!("{field}: {message}"))
},
IssuanceError::MalformedField {
field,
reason,
source,
} => internal::rejected(Self::invalid_request(format!("{field}: {reason}")), source),
IssuanceError::UnsupportedGrantType { grant_type } => {
Self::unsupported_grant_type(format!("Grant type '{grant_type}' is not supported"))
},
IssuanceError::InvalidClient => Self::invalid_client("Client authentication failed"),
IssuanceError::InvalidGrant { reason } => Self::invalid_grant(reason),
IssuanceError::RejectedGrant { reason, source } => {
internal::rejected(Self::invalid_grant(reason), source)
},
IssuanceError::InvalidRefreshToken { reason } => {
Self::invalid_grant(format!("Refresh token invalid: {reason}"))
},
IssuanceError::InvalidCredentials => Self::invalid_grant("Invalid credentials"),
IssuanceError::InvalidClientSecret => Self::invalid_client("Invalid client secret"),
IssuanceError::ExpiredCode => Self::invalid_grant("Authorization code expired"),
IssuanceError::ServerError { context, source } => {
internal::server_error(context, source)
},
IssuanceError::InvalidTarget { message } => Self::invalid_target(message),
IssuanceError::InvalidScope { message } => Self::invalid_scope(message),
IssuanceError::IdJagRejected(error) => Self::invalid_grant(error.to_string()),
IssuanceError::BoundResource(error) => Self::invalid_target(error.to_string()),
IssuanceError::Oauth(error) => Self::from(error),
}
}
}