oauth2_amazon/
authorization_code_grant.rs1use oauth2_client::{
2 authorization_code_grant::provider_ext::ProviderExtAuthorizationCodeGrantPkceSupportType,
3 re_exports::{ClientId, ClientSecret, RedirectUri, Url, UrlParseError},
4 Provider, ProviderExtAuthorizationCodeGrant,
5};
6
7use crate::{token_url, AmazonScope, AmazonTokenUrlRegion, AUTHORIZATION_URL};
8
9#[derive(Debug, Clone)]
10pub struct AmazonProviderWithWebServices {
11 client_id: ClientId,
12 client_secret: ClientSecret,
13 redirect_uri: RedirectUri,
14 token_endpoint_url: Url,
16 authorization_endpoint_url: Url,
17}
18impl AmazonProviderWithWebServices {
19 pub fn new(
20 client_id: ClientId,
21 client_secret: ClientSecret,
22 redirect_uri: RedirectUri,
23 token_url_region: impl Into<Option<AmazonTokenUrlRegion>>,
24 ) -> Result<Self, UrlParseError> {
25 Ok(Self {
26 client_id,
27 client_secret,
28 redirect_uri,
29 token_endpoint_url: token_url(token_url_region).parse()?,
30 authorization_endpoint_url: AUTHORIZATION_URL.parse()?,
31 })
32 }
33}
34impl Provider for AmazonProviderWithWebServices {
35 type Scope = AmazonScope;
36
37 fn client_id(&self) -> Option<&ClientId> {
38 Some(&self.client_id)
39 }
40
41 fn client_secret(&self) -> Option<&ClientSecret> {
42 Some(&self.client_secret)
43 }
44
45 fn token_endpoint_url(&self) -> &Url {
46 &self.token_endpoint_url
47 }
48}
49impl ProviderExtAuthorizationCodeGrant for AmazonProviderWithWebServices {
50 fn redirect_uri(&self) -> Option<&RedirectUri> {
51 Some(&self.redirect_uri)
52 }
53
54 fn pkce_support_type(&self) -> Option<ProviderExtAuthorizationCodeGrantPkceSupportType> {
55 Some(ProviderExtAuthorizationCodeGrantPkceSupportType::Yes)
56 }
57
58 fn scopes_default(&self) -> Option<Vec<<Self as Provider>::Scope>> {
59 Some(vec![AmazonScope::Profile])
60 }
61
62 fn authorization_endpoint_url(&self) -> &Url {
63 &self.authorization_endpoint_url
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 use oauth2_client::{
72 authorization_code_grant::{AccessTokenEndpoint, AuthorizationEndpoint},
73 re_exports::{Endpoint as _, Response},
74 };
75
76 #[test]
77 fn authorization_request() -> Result<(), Box<dyn std::error::Error>> {
78 let provider = AmazonProviderWithWebServices::new(
79 "CLIENT_ID".to_owned(),
80 "CLIENT_SECRET".to_owned(),
81 RedirectUri::new("https://client.example.com/cb")?,
82 None,
83 )?;
84
85 let request = AuthorizationEndpoint::new(
86 &provider,
87 vec![AmazonScope::Profile, AmazonScope::PostalCode],
88 )
89 .configure(|x| x.state = Some("STATE".to_owned()))
90 .render_request()?;
91
92 assert_eq!(request.uri(), "https://www.amazon.com/ap/oa?response_type=code&client_id=CLIENT_ID&redirect_uri=https%3A%2F%2Fclient.example.com%2Fcb&scope=profile+postal_code&state=STATE");
93
94 Ok(())
95 }
96
97 #[test]
98 fn access_token_request() -> Result<(), Box<dyn std::error::Error>> {
99 let provider = AmazonProviderWithWebServices::new(
100 "CLIENT_ID".to_owned(),
101 "CLIENT_SECRET".to_owned(),
102 RedirectUri::new("https://client.example.com/cb")?,
103 None,
104 )?;
105
106 let request = AccessTokenEndpoint::new(&provider, "CODE".to_owned()).render_request()?;
107
108 assert_eq!(request.body(), b"grant_type=authorization_code&code=CODE&redirect_uri=https%3A%2F%2Fclient.example.com%2Fcb&client_id=CLIENT_ID&client_secret=CLIENT_SECRET");
109
110 Ok(())
111 }
112
113 #[test]
114 fn access_token_response() -> Result<(), Box<dyn std::error::Error>> {
115 let provider = AmazonProviderWithWebServices::new(
116 "CLIENT_ID".to_owned(),
117 "CLIENT_SECRET".to_owned(),
118 RedirectUri::new("https://client.example.com/cb")?,
119 None,
120 )?;
121
122 let response_body = include_str!(
123 "../tests/response_body_json_files/access_token_with_authorization_code_grant.json"
124 );
125 let body_ret = AccessTokenEndpoint::new(&provider, "CODE".to_owned())
126 .parse_response(Response::builder().body(response_body.as_bytes().to_vec())?)?;
127
128 match body_ret {
129 Ok(_body) => {}
130 Err(body) => panic!("{body:?}"),
131 }
132
133 Ok(())
134 }
135}