Skip to main content

alibi_plugins/oauth/providers/
google.rs

1use super::{OAuthAuthorizationPolicy, OAuthProvider, OAuthUserInfo};
2use serde_json::Map;
3impl OAuthProvider {
4    #[must_use]
5    pub fn with_hosted_domain(mut self, domain: impl Into<String>) -> Self {
6        let domain = domain.into();
7        self.authorization_params.retain(|(key, _)| key != "hd");
8        self.authorization_params
9            .push(("hd".into(), domain.clone()));
10        self.hosted_domain = Some(domain);
11        self
12    }
13
14    #[must_use]
15    pub fn google(client_id: &str, client_secret: &str) -> Self {
16        Self {
17            client_id: client_id.to_owned(),
18            additional_client_ids: Vec::new(),
19            hosted_domain: None,
20            require_email_verification: false,
21            client_secret: client_secret.to_owned(),
22            auth_url: "https://accounts.google.com/o/oauth2/v2/auth".to_owned(),
23            token_url: "https://oauth2.googleapis.com/token".to_owned(),
24            user_info_url: Some("https://www.googleapis.com/oauth2/v3/userinfo".to_owned()),
25            scopes: vec![
26                "email".to_owned(),
27                "profile".to_owned(),
28                "openid".to_owned(),
29            ],
30            authorization: Some(OAuthAuthorizationPolicy {
31                require_client_secret: true,
32                ..Default::default()
33            }),
34            allowed_request_params: Vec::new(),
35            authorization_params: vec![("include_granted_scopes".to_owned(), "true".to_owned())],
36            account_subject: None,
37            map_user_info: Some(|v| {
38                Ok(OAuthUserInfo {
39                    additional_fields: Map::default(),
40                    id: v
41                        .get("sub")
42                        .and_then(|v| v.as_str())
43                        .ok_or("missing sub")?
44                        .to_owned(),
45                    email: v
46                        .get("email")
47                        .and_then(|v| v.as_str())
48                        .unwrap_or_default()
49                        .to_owned(),
50                    name: v.get("name").and_then(|v| v.as_str()).map(String::from),
51                    image: v.get("picture").and_then(|v| v.as_str()).map(String::from),
52                    // Google may send the claim as the string "true"; One Tap
53                    // reads the mapped value with Better Auth's `toBoolean`.
54                    email_verified: v.get("email_verified").is_some_and(|value| {
55                        value.as_bool() == Some(true) || value.as_str() == Some("true")
56                    }),
57                })
58            }),
59            get_user_info: None,
60            refresh_access_token: None,
61            verify_id_token: None,
62            id_token: Some(crate::oauth::id_token::OAuthIdTokenConfig::google()),
63            disable_id_token_sign_in: false,
64            disable_implicit_sign_up: false,
65            disable_sign_up: false,
66            allow_idp_initiated: false,
67            override_user_info_on_sign_in: false,
68        }
69    }
70}