io_oauth/2.0/
refresh-access-token.rs1use std::{borrow::Cow, collections::HashSet};
6
7use http::{header::CONTENT_TYPE, request};
8use io_http::v1_1::coroutines::Send;
9use io_stream::Io;
10use secrecy::{ExposeSecret, SecretString};
11use url::form_urlencoded::Serializer;
12
13use super::issue_access_token::{
14 AccessTokenResponse, IssueAccessTokenErrorParams, IssueAccessTokenSuccessParams,
15};
16
17pub struct RefreshAccessToken(Send);
25
26impl RefreshAccessToken {
27 pub fn new(
29 request: request::Builder,
30 body: RefreshAccessTokenParams<'_>,
31 ) -> http::Result<Self> {
32 let request = request
33 .header(CONTENT_TYPE, "application/x-www-form-urlencoded")
34 .body(body.to_string().into_bytes())?;
35
36 let send = Send::new(request);
37 Ok(Self(send))
38 }
39
40 pub fn resume(
42 &mut self,
43 input: Option<Io>,
44 ) -> Result<serde_json::Result<AccessTokenResponse>, Io> {
45 let response = self.0.resume(input)?;
46 let body = response.body().as_slice();
47
48 if response.status().is_success() {
49 match IssueAccessTokenSuccessParams::try_from(body) {
50 Ok(res) => Ok(Ok(Ok(res))),
51 Err(err) => Ok(Err(err)),
52 }
53 } else {
54 match IssueAccessTokenErrorParams::try_from(body) {
55 Ok(res) => Ok(Ok(Err(res))),
56 Err(err) => Ok(Err(err)),
57 }
58 }
59 }
60}
61
62#[derive(Debug)]
72pub struct RefreshAccessTokenParams<'a> {
73 pub client_id: String,
74 pub refresh_token: SecretString,
75 pub scopes: HashSet<Cow<'a, str>>,
76}
77
78impl<'a> RefreshAccessTokenParams<'a> {
79 pub fn new(client_id: impl ToString, refresh_token: impl Into<SecretString>) -> Self {
80 Self {
81 client_id: client_id.to_string(),
82 refresh_token: refresh_token.into(),
83 scopes: HashSet::new(),
84 }
85 }
86
87 pub fn to_serializer(&self) -> Serializer<'a, String> {
88 let mut serializer = Serializer::new(String::new());
89
90 serializer.append_pair("grant_type", "refresh_token");
91 serializer.append_pair("client_id", &self.client_id);
92 serializer.append_pair("refresh_token", &self.refresh_token.expose_secret());
93
94 if !self.scopes.is_empty() {
95 let mut scope = String::new();
96 let mut glue = "";
97
98 for token in &self.scopes {
99 scope.push_str(glue);
100 scope.push_str(token);
101 glue = " ";
102 }
103
104 serializer.append_pair("scope", &scope);
105 }
106
107 serializer
108 }
109}
110
111impl ToString for RefreshAccessTokenParams<'_> {
112 fn to_string(&self) -> String {
113 self.to_serializer().finish()
114 }
115}