use matrix_sdk_base::deserialized_responses::PrivOwnedStr;
use oauth2::ErrorResponseType;
pub use oauth2::{
ConfigurationError, HttpClientError, RequestTokenError, RevocationErrorResponseType,
StandardErrorResponse,
basic::{
BasicErrorResponse, BasicErrorResponseType, BasicRequestTokenError,
BasicRevocationErrorResponse,
},
};
use ruma::{
api::client::discovery::get_authorization_server_metadata::v1::AuthorizationServerMetadataUrlError,
serde::StringEnum,
};
#[cfg(feature = "e2e-encryption")]
pub use super::cross_process::CrossProcessRefreshLockError;
pub type OAuthRequestError<T> =
RequestTokenError<HttpClientError<reqwest::Error>, StandardErrorResponse<T>>;
#[derive(Debug, Clone, thiserror::Error)]
#[non_exhaustive]
pub enum RedirectUriQueryParseError {
#[error("No query in URI")]
MissingQuery,
#[error("Query is not using one of the defined formats")]
UnknownFormat,
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum OAuthError {
#[error("authorization server discovery failed: {0}")]
Discovery(#[from] OAuthDiscoveryError),
#[error("client registration failed: {0}")]
ClientRegistration(#[from] OAuthClientRegistrationError),
#[error("client not registered")]
NotRegistered,
#[error("client not authenticated")]
NotAuthenticated,
#[error("authorization code grant failed: {0}")]
AuthorizationCode(#[from] OAuthAuthorizationCodeError),
#[error("failed to refresh token: {0}")]
RefreshToken(OAuthRequestError<BasicErrorResponseType>),
#[error("failed to log out: {0}")]
Logout(#[from] OAuthTokenRevocationError),
#[cfg(feature = "e2e-encryption")]
#[error(transparent)]
LockError(#[from] CrossProcessRefreshLockError),
#[error("new logged-in session is different than current client session")]
SessionMismatch,
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum OAuthDiscoveryError {
#[error("OAuth 2.0 is not supported by the homeserver")]
NotSupported,
#[error(transparent)]
Http(#[from] crate::HttpError),
#[error(transparent)]
Json(#[from] serde_json::Error),
#[error(transparent)]
Validation(#[from] AuthorizationServerMetadataUrlError),
#[error(transparent)]
Url(#[from] url::ParseError),
#[error(transparent)]
Oidc(#[from] OAuthRequestError<BasicErrorResponseType>),
}
impl OAuthDiscoveryError {
pub fn is_not_supported(&self) -> bool {
matches!(self, Self::NotSupported)
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum OAuthAuthorizationCodeError {
#[error(transparent)]
RedirectUri(#[from] RedirectUriQueryParseError),
#[error("authorization cancelled by the user")]
Cancelled,
#[error("authorization failed: {0}")]
Authorization(StandardErrorResponse<AuthorizationCodeErrorResponseType>),
#[error("authorization state value is unexpected")]
InvalidState,
#[error("failed to request token: {0}")]
RequestToken(OAuthRequestError<BasicErrorResponseType>),
}
impl From<StandardErrorResponse<AuthorizationCodeErrorResponseType>>
for OAuthAuthorizationCodeError
{
fn from(value: StandardErrorResponse<AuthorizationCodeErrorResponseType>) -> Self {
if *value.error() == AuthorizationCodeErrorResponseType::AccessDenied {
Self::Cancelled
} else {
Self::Authorization(value)
}
}
}
#[derive(Clone, StringEnum)]
#[ruma_enum(rename_all = "snake_case")]
#[non_exhaustive]
pub enum AuthorizationCodeErrorResponseType {
InvalidRequest,
UnauthorizedClient,
AccessDenied,
UnsupportedResponseType,
InvalidScope,
ServerError,
TemporarilyUnavailable,
#[doc(hidden)]
_Custom(PrivOwnedStr),
}
impl ErrorResponseType for AuthorizationCodeErrorResponseType {}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum OAuthTokenRevocationError {
#[error(transparent)]
Url(ConfigurationError),
#[error("failed to revoke token: {0}")]
Revoke(OAuthRequestError<RevocationErrorResponseType>),
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum OAuthClientRegistrationError {
#[error("dynamic client registration is not supported")]
NotSupported,
#[error("failed to serialize client metadata: {0}")]
IntoJson(serde_json::Error),
#[error(transparent)]
OAuth(#[from] OAuthRequestError<ClientRegistrationErrorResponseType>),
#[error("failed to deserialize registration response: {0}")]
FromJson(serde_json::Error),
}
#[derive(Clone, StringEnum)]
#[ruma_enum(rename_all = "snake_case")]
#[non_exhaustive]
pub enum ClientRegistrationErrorResponseType {
InvalidRedirectUri,
InvalidClientMetadata,
InvalidSoftwareStatement,
UnapprovedSoftwareStatement,
#[doc(hidden)]
_Custom(PrivOwnedStr),
}
impl ErrorResponseType for ClientRegistrationErrorResponseType {}