1use reqwest::Client;
2use serde::Deserialize;
3use std::collections::HashMap;
4
5#[derive(Deserialize, Debug)]
6pub struct TokenExchangeResponse {
7 access_token: String,
8 token_type: String,
9 expires_in: u64,
10 scope: Option<String>,
11 issued_token_type: Option<String>,
12}
13
14impl TokenExchangeResponse {
15 pub fn access_token(&self) -> &str {
16 &self.access_token
17 }
18
19 pub fn token_type(&self) -> &str {
20 &self.token_type
21 }
22
23 pub fn issued_token_type(&self) -> &Option<String> {
24 &self.issued_token_type
25 }
26
27 pub fn expires(&self) -> u64 {
28 self.expires_in
29 }
30
31 pub fn scope(&self) -> &Option<String> {
32 &self.scope
33 }
34}
35
36pub(crate) async fn perform_token_exchange(
44 token_endpoint: &str,
45 client_id: &str,
46 client_secret: &str,
47 subject_token: &str,
48 audience: &str,
49) -> Result<TokenExchangeResponse, reqwest::Error> {
50 let client = Client::new();
51
52 let mut params = HashMap::new();
53 params.insert(
54 "grant_type",
55 "urn:ietf:params:oauth:grant-type:token-exchange",
56 );
57 params.insert("subject_token", subject_token);
58 params.insert(
59 "subject_token_type",
60 "urn:ietf:params:oauth:token-type:access_token",
61 );
62 params.insert("client_id", client_id);
63 params.insert("client_secret", client_secret);
64 params.insert("audience", audience);
66
67 println!("params: {:?}", params);
68 let resp = client
69 .post(token_endpoint)
70 .form(¶ms)
71 .send()
72 .await?
73 .error_for_status()?
74 .json::<TokenExchangeResponse>()
75 .await?;
76
77 Ok(resp)
78}