oauth2_client/device_authorization_grant/
flow.rs1use http_api_client::{
2 Client, ClientRespondEndpointError, RetryableClient,
3 RetryableClientRespondEndpointUntilDoneError,
4};
5use oauth2_core::{
6 device_authorization_grant::{
7 device_access_token_response::{
8 ErrorBody as DAT_RES_ErrorBody, SuccessfulBody as DAT_RES_SuccessfulBody,
9 },
10 device_authorization_response::{
11 ErrorBody as DA_RES_ErrorBody, UserCode, VerificationUri, VerificationUriComplete,
12 },
13 },
14 serde::{de::DeserializeOwned, Serialize},
15 types::Scope,
16};
17
18use crate::ProviderExtDeviceAuthorizationGrant;
19
20use super::{
21 DeviceAccessTokenEndpoint, DeviceAccessTokenEndpointError, DeviceAuthorizationEndpoint,
22 DeviceAuthorizationEndpointError,
23};
24
25#[derive(Debug, Clone)]
29pub struct Flow<C1, C2>
30where
31 C1: Client,
32 C2: RetryableClient,
33{
34 pub client_with_auth: C1,
35 pub client_with_token: C2,
36}
37impl<C1, C2> Flow<C1, C2>
38where
39 C1: Client,
40 C2: RetryableClient,
41{
42 pub fn new(client_with_auth: C1, client_with_token: C2) -> Self {
43 Self {
44 client_with_auth,
45 client_with_token,
46 }
47 }
48}
49
50impl<C1, C2> Flow<C1, C2>
51where
52 C1: Client + Send + Sync,
53 C2: RetryableClient + Send + Sync,
54{
55 pub async fn execute<SCOPE, UI>(
56 &self,
57 provider: &(dyn ProviderExtDeviceAuthorizationGrant<Scope = SCOPE> + Send + Sync),
58 scopes: impl Into<Option<Vec<SCOPE>>>,
59 user_interaction: UI,
60 ) -> Result<DAT_RES_SuccessfulBody<SCOPE>, FlowExecuteError>
61 where
62 SCOPE: Scope + Serialize + DeserializeOwned + Send + Sync,
63 UI: FnOnce(UserCode, VerificationUri, Option<VerificationUriComplete>),
64 {
65 let scopes = scopes.into().or_else(|| provider.scopes_default());
67
68 let device_authorization_endpoint = DeviceAuthorizationEndpoint::new(provider, scopes);
69
70 let device_authorization_ret = self
71 .client_with_auth
72 .respond_endpoint(&device_authorization_endpoint)
73 .await
74 .map_err(|err| match err {
75 ClientRespondEndpointError::RespondFailed(err) => {
76 FlowExecuteError::DeviceAuthorizationEndpointRespondFailed(Box::new(err))
77 }
78 ClientRespondEndpointError::EndpointRenderRequestFailed(err) => {
79 FlowExecuteError::DeviceAuthorizationEndpointError(err)
80 }
81 ClientRespondEndpointError::EndpointParseResponseFailed(err) => {
82 FlowExecuteError::DeviceAuthorizationEndpointError(err)
83 }
84 })?;
85
86 let device_authorization_successful_body =
87 device_authorization_ret.map_err(FlowExecuteError::DeviceAuthorizationFailed)?;
88
89 user_interaction(
91 device_authorization_successful_body.user_code.to_owned(),
92 device_authorization_successful_body
93 .verification_uri
94 .to_owned(),
95 device_authorization_successful_body
96 .verification_uri_complete
97 .to_owned(),
98 );
99
100 let device_access_token_endpoint =
102 DeviceAccessTokenEndpoint::new(provider, device_authorization_successful_body);
103
104 let device_access_token_ret = self
105 .client_with_token
106 .respond_endpoint_until_done(&device_access_token_endpoint)
107 .await
108 .map_err(|err| match err {
109 RetryableClientRespondEndpointUntilDoneError::RespondFailed(err) => {
110 FlowExecuteError::DeviceAccessTokenEndpointRespondFailed(Box::new(err))
111 }
112 RetryableClientRespondEndpointUntilDoneError::EndpointRenderRequestFailed(err) => {
113 FlowExecuteError::DeviceAccessTokenEndpointError(err)
114 }
115 RetryableClientRespondEndpointUntilDoneError::EndpointParseResponseFailed(err) => {
116 FlowExecuteError::DeviceAccessTokenEndpointError(err)
117 }
118 RetryableClientRespondEndpointUntilDoneError::ReachedMaxRetries => {
119 FlowExecuteError::DeviceAccessTokenEndpointErrorWithReachedMaxRetries
120 }
121 })?;
122
123 let device_access_token_successful_body =
124 device_access_token_ret.map_err(FlowExecuteError::DeviceAccessTokenFailed)?;
125
126 Ok(device_access_token_successful_body)
127 }
128}
129
130#[derive(thiserror::Error, Debug)]
131pub enum FlowExecuteError {
132 #[error("DeviceAuthorizationEndpointRespondFailed {0}")]
133 DeviceAuthorizationEndpointRespondFailed(Box<dyn std::error::Error + Send + Sync>),
134 #[error("DeviceAuthorizationEndpointError {0}")]
135 DeviceAuthorizationEndpointError(DeviceAuthorizationEndpointError),
136 #[error("DeviceAuthorizationFailed {0:?}")]
137 DeviceAuthorizationFailed(DA_RES_ErrorBody),
138 #[error("DeviceAccessTokenEndpointRespondFailed {0}")]
140 DeviceAccessTokenEndpointRespondFailed(Box<dyn std::error::Error + Send + Sync>),
141 #[error("DeviceAccessTokenEndpointError {0}")]
142 DeviceAccessTokenEndpointError(DeviceAccessTokenEndpointError),
143 #[error("DeviceAccessTokenEndpointErrorWithReachedMaxRetries")]
144 DeviceAccessTokenEndpointErrorWithReachedMaxRetries,
145 #[error("DeviceAccessTokenFailed {0:?}")]
146 DeviceAccessTokenFailed(DAT_RES_ErrorBody),
147}