oauth2_google/
device_authorization_grant.rs

1use oauth2_client::{
2    re_exports::{ClientId, ClientSecret, Url, UrlParseError},
3    Provider, ProviderExtDeviceAuthorizationGrant,
4};
5
6use crate::{GoogleScope, DEVICE_AUTHORIZATION_URL, TOKEN_URL};
7
8#[derive(Debug, Clone)]
9pub struct GoogleProviderForTvAndDeviceApps {
10    client_id: ClientId,
11    client_secret: ClientSecret,
12    //
13    token_endpoint_url: Url,
14    device_authorization_endpoint_url: Url,
15}
16impl GoogleProviderForTvAndDeviceApps {
17    pub fn new(client_id: ClientId, client_secret: ClientSecret) -> Result<Self, UrlParseError> {
18        Ok(Self {
19            client_id,
20            client_secret,
21            token_endpoint_url: TOKEN_URL.parse()?,
22            device_authorization_endpoint_url: DEVICE_AUTHORIZATION_URL.parse()?,
23        })
24    }
25}
26impl Provider for GoogleProviderForTvAndDeviceApps {
27    type Scope = GoogleScope;
28
29    fn client_id(&self) -> Option<&ClientId> {
30        Some(&self.client_id)
31    }
32
33    fn client_secret(&self) -> Option<&ClientSecret> {
34        Some(&self.client_secret)
35    }
36
37    fn token_endpoint_url(&self) -> &Url {
38        &self.token_endpoint_url
39    }
40}
41impl ProviderExtDeviceAuthorizationGrant for GoogleProviderForTvAndDeviceApps {
42    fn device_authorization_endpoint_url(&self) -> &Url {
43        &self.device_authorization_endpoint_url
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    use oauth2_client::{
52        device_authorization_grant::{
53            provider_ext::DeviceAuthorizationResponseSuccessfulBody, DeviceAccessTokenEndpoint,
54        },
55        re_exports::RetryableEndpoint as _,
56    };
57
58    #[test]
59    fn access_token_request() -> Result<(), Box<dyn std::error::Error>> {
60        let provider = GoogleProviderForTvAndDeviceApps::new(
61            "CLIENT_ID".to_owned(),
62            "CLIENT_SECRET".to_owned(),
63        )?;
64
65        let endpoint = DeviceAccessTokenEndpoint::new(
66            &provider,
67            DeviceAuthorizationResponseSuccessfulBody::new(
68                "DEVICE_CODE".to_owned(),
69                "".to_owned(),
70                "https://example.com".parse()?,
71                None,
72                0,
73                Some(5),
74            ),
75        );
76
77        let request = endpoint.render_request(None)?;
78
79        assert_eq!(request.body(), b"grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code&device_code=DEVICE_CODE&client_id=CLIENT_ID&client_secret=CLIENT_SECRET");
80
81        Ok(())
82    }
83}