oauth2_client/device_authorization_grant/
device_authorization_endpoint.rs

1use http_api_client_endpoint::{Body, Endpoint, Request, Response};
2use oauth2_core::{
3    access_token_response::GENERAL_ERROR_BODY_KEY_ERROR,
4    device_authorization_grant::{
5        device_authorization_request::{
6            Body as REQ_Body, CONTENT_TYPE as REQ_CONTENT_TYPE, METHOD as REQ_METHOD,
7        },
8        device_authorization_response::{
9            ErrorBody as RES_ErrorBody, SuccessfulBody as RES_SuccessfulBody,
10            CONTENT_TYPE as RES_CONTENT_TYPE,
11        },
12    },
13    http::{
14        header::{ACCEPT, CONTENT_TYPE},
15        Error as HttpError,
16    },
17    serde::Serialize,
18    types::Scope,
19};
20use serde_json::{Error as SerdeJsonError, Map, Value};
21use serde_urlencoded::ser::Error as SerdeUrlencodedSerError;
22
23use crate::ProviderExtDeviceAuthorizationGrant;
24
25//
26#[derive(Clone)]
27pub struct DeviceAuthorizationEndpoint<'a, SCOPE>
28where
29    SCOPE: Scope,
30{
31    provider: &'a (dyn ProviderExtDeviceAuthorizationGrant<Scope = SCOPE> + Send + Sync),
32    scopes: Option<Vec<SCOPE>>,
33}
34impl<'a, SCOPE> DeviceAuthorizationEndpoint<'a, SCOPE>
35where
36    SCOPE: Scope,
37{
38    pub fn new(
39        provider: &'a (dyn ProviderExtDeviceAuthorizationGrant<Scope = SCOPE> + Send + Sync),
40        scopes: impl Into<Option<Vec<SCOPE>>>,
41    ) -> Self {
42        Self {
43            provider,
44            scopes: scopes.into(),
45        }
46    }
47}
48
49impl<'a, SCOPE> Endpoint for DeviceAuthorizationEndpoint<'a, SCOPE>
50where
51    SCOPE: Scope + Serialize,
52{
53    type RenderRequestError = DeviceAuthorizationEndpointError;
54
55    type ParseResponseOutput = Result<RES_SuccessfulBody, RES_ErrorBody>;
56    type ParseResponseError = DeviceAuthorizationEndpointError;
57
58    fn render_request(&self) -> Result<Request<Body>, Self::RenderRequestError> {
59        let mut body = REQ_Body::new(
60            self.provider.client_id().cloned(),
61            self.scopes.to_owned().map(Into::into),
62        );
63        if let Some(extra) = self.provider.device_authorization_request_body_extra() {
64            body.set_extra(extra);
65        }
66
67        if let Some(request_ret) = self.provider.device_authorization_request_rendering(&body) {
68            let request = request_ret.map_err(|err| {
69                DeviceAuthorizationEndpointError::CustomRenderingRequestFailed(err)
70            })?;
71            return Ok(request);
72        }
73
74        let body_str = serde_urlencoded::to_string(body)
75            .map_err(DeviceAuthorizationEndpointError::SerRequestBodyFailed)?;
76
77        let request = Request::builder()
78            .method(REQ_METHOD)
79            .uri(self.provider.device_authorization_endpoint_url().as_str())
80            .header(CONTENT_TYPE, REQ_CONTENT_TYPE.to_string())
81            .header(ACCEPT, RES_CONTENT_TYPE.to_string())
82            .body(body_str.as_bytes().to_vec())
83            .map_err(DeviceAuthorizationEndpointError::MakeRequestFailed)?;
84
85        Ok(request)
86    }
87
88    fn parse_response(
89        &self,
90        response: Response<Body>,
91    ) -> Result<Self::ParseResponseOutput, Self::ParseResponseError> {
92        if let Some(body_ret_ret) = self
93            .provider
94            .device_authorization_response_parsing(&response)
95        {
96            let body_ret = body_ret_ret.map_err(|err| {
97                DeviceAuthorizationEndpointError::CustomParsingResponseFailed(err)
98            })?;
99
100            return Ok(body_ret);
101        }
102
103        if response.status().is_success() {
104            let map = serde_json::from_slice::<Map<String, Value>>(response.body())
105                .map_err(DeviceAuthorizationEndpointError::DeResponseBodyFailed)?;
106            if !map.contains_key(GENERAL_ERROR_BODY_KEY_ERROR) {
107                let body = serde_json::from_slice::<RES_SuccessfulBody>(response.body())
108                    .map_err(DeviceAuthorizationEndpointError::DeResponseBodyFailed)?;
109
110                return Ok(Ok(body));
111            }
112        }
113
114        let body = serde_json::from_slice::<RES_ErrorBody>(response.body())
115            .map_err(DeviceAuthorizationEndpointError::DeResponseBodyFailed)?;
116        Ok(Err(body))
117    }
118}
119
120#[derive(thiserror::Error, Debug)]
121pub enum DeviceAuthorizationEndpointError {
122    #[error("CustomRenderingRequestFailed {0}")]
123    CustomRenderingRequestFailed(Box<dyn std::error::Error + Send + Sync>),
124    //
125    #[error("SerRequestBodyFailed {0}")]
126    SerRequestBodyFailed(SerdeUrlencodedSerError),
127    #[error("MakeRequestFailed {0}")]
128    MakeRequestFailed(HttpError),
129    //
130    #[error("CustomParsingResponseFailed {0}")]
131    CustomParsingResponseFailed(Box<dyn std::error::Error + Send + Sync>),
132    //
133    #[error("DeResponseBodyFailed {0}")]
134    DeResponseBodyFailed(SerdeJsonError),
135}