oauth2_client/device_authorization_grant/
device_authorization_endpoint.rs1use 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#[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 #[error("SerRequestBodyFailed {0}")]
126 SerRequestBodyFailed(SerdeUrlencodedSerError),
127 #[error("MakeRequestFailed {0}")]
128 MakeRequestFailed(HttpError),
129 #[error("CustomParsingResponseFailed {0}")]
131 CustomParsingResponseFailed(Box<dyn std::error::Error + Send + Sync>),
132 #[error("DeResponseBodyFailed {0}")]
134 DeResponseBodyFailed(SerdeJsonError),
135}