Skip to main content

rustauth_core/auth/oauth/
errors.rs

1use std::error::Error;
2use std::fmt;
3
4use crate::error::RustAuthError;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum OAuthUserInfoError {
8    AccountNotLinked,
9    SignupDisabled,
10    UnableToCreateUser,
11    UnableToCreateSession,
12    UnableToLinkAccount,
13}
14
15impl OAuthUserInfoError {
16    pub fn code_str(self) -> &'static str {
17        match self {
18            Self::AccountNotLinked => "account_not_linked",
19            Self::SignupDisabled => "signup_disabled",
20            Self::UnableToCreateUser => "unable_to_create_user",
21            Self::UnableToCreateSession => "unable_to_create_session",
22            Self::UnableToLinkAccount => "unable_to_link_account",
23        }
24    }
25
26    pub fn message(self) -> &'static str {
27        match self {
28            Self::AccountNotLinked => "Account not linked",
29            Self::SignupDisabled => "Signup disabled",
30            Self::UnableToCreateUser => "Unable to create user",
31            Self::UnableToCreateSession => "Unable to create session",
32            Self::UnableToLinkAccount => "Unable to link account",
33        }
34    }
35}
36
37impl fmt::Display for OAuthUserInfoError {
38    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
39        write!(formatter, "{}: {}", self.code_str(), self.message())
40    }
41}
42
43impl Error for OAuthUserInfoError {}
44
45impl From<OAuthUserInfoError> for RustAuthError {
46    fn from(error: OAuthUserInfoError) -> Self {
47        Self::OAuth(error.to_string())
48    }
49}
50
51const HANDLING_DOCS_URL: &str =
52    "https://www.better-auth.com/docs/concepts/oauth#handling-providers-without-email";
53
54pub fn missing_email_log_message(provider_id: &str, source: Option<&str>) -> String {
55    let subject = if source == Some("generic") {
56        format!("Generic OAuth provider \"{provider_id}\"")
57    } else {
58        format!("Provider \"{provider_id}\"")
59    };
60    let where_text = if source == Some("id_token") {
61        " in the id token"
62    } else {
63        ""
64    };
65    format!(
66        "{subject} did not return an email{where_text}. Either request the provider's email scope, or synthesize one via `mapProfileToUser`. See {HANDLING_DOCS_URL}"
67    )
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn oauth_user_info_error_bridges_to_rustauth_error() {
76        let error = OAuthUserInfoError::AccountNotLinked;
77        let bridged: RustAuthError = error.into();
78        assert_eq!(
79            bridged,
80            RustAuthError::OAuth("account_not_linked: Account not linked".to_owned())
81        );
82    }
83
84    #[test]
85    fn oauth_user_info_error_code_str_matches_http_helpers() {
86        assert_eq!(
87            OAuthUserInfoError::SignupDisabled.code_str(),
88            "signup_disabled"
89        );
90        assert_eq!(
91            OAuthUserInfoError::UnableToLinkAccount.message(),
92            "Unable to link account"
93        );
94    }
95}