oauth2_google/extensions/
user_info_endpoint.rs

1use oauth2_client::{
2    extensions::{EndpointParseResponseError, EndpointRenderRequestError, UserInfo},
3    re_exports::{serde_json, Body, Endpoint, Request, Response},
4};
5
6use super::{
7    internal_oauth2_v3_user_info_endpoint::{
8        Oauth2V3UserInfo, Oauth2V3UserInfoEndpoint, Oauth2V3UserInfoEndpointError,
9    },
10    internal_oidc_v1_userinfo_endpoint::{
11        OidcV1UserInfo, OidcV1UserInfoEndpoint, OidcV1UserInfoEndpointError,
12    },
13};
14
15//
16#[derive(Debug, Clone)]
17pub struct GoogleUserInfoEndpoint {
18    inner: Inner,
19}
20#[derive(Debug, Clone)]
21enum Inner {
22    Oauth2V3UserInfoEndpoint(Oauth2V3UserInfoEndpoint),
23    OidcV1UserInfoEndpoint(OidcV1UserInfoEndpoint),
24}
25impl GoogleUserInfoEndpoint {
26    pub fn new(access_token: impl AsRef<str>, has_openid_scope: bool) -> Self {
27        Self {
28            inner: if has_openid_scope {
29                Inner::OidcV1UserInfoEndpoint(OidcV1UserInfoEndpoint::new(access_token))
30            } else {
31                Inner::Oauth2V3UserInfoEndpoint(Oauth2V3UserInfoEndpoint::new(access_token))
32            },
33        }
34    }
35}
36
37impl Endpoint for GoogleUserInfoEndpoint {
38    type RenderRequestError = EndpointRenderRequestError;
39
40    type ParseResponseOutput = UserInfo;
41    type ParseResponseError = EndpointParseResponseError;
42
43    fn render_request(&self) -> Result<Request<Body>, Self::RenderRequestError> {
44        match &self.inner {
45            Inner::Oauth2V3UserInfoEndpoint(ep) => ep.render_request().map_err(Into::into),
46            Inner::OidcV1UserInfoEndpoint(ep) => ep.render_request().map_err(Into::into),
47        }
48    }
49
50    fn parse_response(
51        &self,
52        response: Response<Body>,
53    ) -> Result<Self::ParseResponseOutput, Self::ParseResponseError> {
54        match &self.inner {
55            Inner::Oauth2V3UserInfoEndpoint(ep) => UserInfo::try_from(ep.parse_response(response)?)
56                .map_err(EndpointParseResponseError::ToOutputFailed),
57            Inner::OidcV1UserInfoEndpoint(ep) => UserInfo::try_from(ep.parse_response(response)?)
58                .map_err(EndpointParseResponseError::ToOutputFailed),
59        }
60    }
61}
62
63//
64impl From<Oauth2V3UserInfoEndpointError> for EndpointRenderRequestError {
65    fn from(err: Oauth2V3UserInfoEndpointError) -> Self {
66        match err {
67            Oauth2V3UserInfoEndpointError::MakeRequestFailed(err) => Self::MakeRequestFailed(err),
68            Oauth2V3UserInfoEndpointError::DeResponseBodyFailed(err) => Self::Other(Box::new(err)),
69        }
70    }
71}
72impl From<Oauth2V3UserInfoEndpointError> for EndpointParseResponseError {
73    fn from(err: Oauth2V3UserInfoEndpointError) -> Self {
74        match err {
75            Oauth2V3UserInfoEndpointError::MakeRequestFailed(err) => Self::Other(Box::new(err)),
76            Oauth2V3UserInfoEndpointError::DeResponseBodyFailed(err) => {
77                Self::DeResponseBodyFailed(err)
78            }
79        }
80    }
81}
82
83//
84impl TryFrom<Oauth2V3UserInfo> for UserInfo {
85    type Error = Box<dyn std::error::Error + Send + Sync>;
86
87    fn try_from(user_info: Oauth2V3UserInfo) -> Result<Self, Self::Error> {
88        Ok(Self {
89            uid: user_info.sub.to_owned(),
90            name: None,
91            email: user_info.email.to_owned(),
92            raw: serde_json::to_value(user_info)
93                .map(|x| x.as_object().cloned())?
94                .ok_or_else(|| "unreachable".to_owned())?,
95        })
96    }
97}
98
99//
100impl From<OidcV1UserInfoEndpointError> for EndpointRenderRequestError {
101    fn from(err: OidcV1UserInfoEndpointError) -> Self {
102        match err {
103            OidcV1UserInfoEndpointError::MakeRequestFailed(err) => Self::MakeRequestFailed(err),
104            OidcV1UserInfoEndpointError::DeResponseBodyFailed(err) => Self::Other(Box::new(err)),
105        }
106    }
107}
108impl From<OidcV1UserInfoEndpointError> for EndpointParseResponseError {
109    fn from(err: OidcV1UserInfoEndpointError) -> Self {
110        match err {
111            OidcV1UserInfoEndpointError::MakeRequestFailed(err) => Self::Other(Box::new(err)),
112            OidcV1UserInfoEndpointError::DeResponseBodyFailed(err) => {
113                Self::DeResponseBodyFailed(err)
114            }
115        }
116    }
117}
118
119//
120impl TryFrom<OidcV1UserInfo> for UserInfo {
121    type Error = Box<dyn std::error::Error + Send + Sync>;
122
123    fn try_from(user_info: OidcV1UserInfo) -> Result<Self, Self::Error> {
124        Ok(Self {
125            uid: user_info.sub.to_owned(),
126            name: user_info.name.to_owned(),
127            email: user_info.email.to_owned(),
128            raw: serde_json::to_value(user_info)
129                .map(|x| x.as_object().cloned())?
130                .ok_or_else(|| "unreachable".to_owned())?,
131        })
132    }
133}