1use std::collections::HashMap;
16
17use serde::{Deserialize, Serialize};
18
19use crate::client::{get_admin_id, get_owner, Client, PostBody, Response};
20use crate::error::Result;
21use crate::serde_util::null_to_default;
22
23#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
26#[serde(rename_all = "camelCase", default)]
27pub struct Token {
28 pub owner: String,
29 pub name: String,
30 pub created_time: String,
31
32 pub application: String,
33 pub organization: String,
34 pub user: String,
35
36 pub code: String,
37 pub access_token: String,
38 pub refresh_token: String,
39 pub access_token_hash: String,
40 pub refresh_token_hash: String,
41 pub expires_in: i32,
42 pub scope: String,
43 pub token_type: String,
44 pub grant_type: String,
45 pub code_challenge: String,
46 pub code_is_used: bool,
47 pub code_expire_in: i64,
48 pub resource: String,
50 #[serde(rename = "dPoPJkt")]
52 pub dpop_jkt: String,
53 pub session_id: String,
54}
55
56#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
58#[serde(default)]
59pub struct IntrospectTokenResult {
60 pub active: bool,
61 pub client_id: String,
62 pub username: String,
63 pub token_type: String,
64 pub exp: u64,
65 pub iat: u64,
66 pub nbf: u64,
67 pub sub: String,
68 #[serde(deserialize_with = "null_to_default")]
69 pub aud: Vec<String>,
70 pub iss: String,
71 pub jti: String,
72}
73
74impl Client {
75 pub async fn get_tokens(&self) -> Result<Vec<Token>> {
77 self.get_list("get-tokens", &[("owner", "admin")]).await
78 }
79
80 pub async fn get_pagination_tokens(
82 &self,
83 p: i32,
84 page_size: i32,
85 query: &[(&str, &str)],
86 ) -> Result<(Vec<Token>, i32)> {
87 self.get_pagination("get-tokens", "admin", p, page_size, query)
88 .await
89 }
90
91 pub async fn get_token(&self, name: &str) -> Result<Option<Token>> {
93 self.get_object("get-token", &[("id", &get_admin_id(name))])
94 .await
95 }
96
97 pub async fn add_token(&self, token: &Token) -> Result<bool> {
99 Ok(self.modify_token("add-token", token, &[]).await?.1)
100 }
101
102 pub async fn update_token(&self, token: &Token) -> Result<bool> {
104 Ok(self.modify_token("update-token", token, &[]).await?.1)
105 }
106
107 pub async fn update_token_for_columns(&self, token: &Token, columns: &[&str]) -> Result<bool> {
109 Ok(self.modify_token("update-token", token, columns).await?.1)
110 }
111
112 pub async fn delete_token(&self, token: &Token) -> Result<bool> {
114 Ok(self.modify_token("delete-token", token, &[]).await?.1)
115 }
116
117 pub async fn introspect_token(
120 &self,
121 token: &str,
122 token_type_hint: &str,
123 ) -> Result<IntrospectTokenResult> {
124 let fields = HashMap::from([
125 ("token".to_string(), token.to_string()),
126 ("token_type_hint".to_string(), token_type_hint.to_string()),
127 ]);
128
129 let url = self.get_url("login/oauth/introspect", &[]);
130 let bytes = self.do_post_bytes_raw(&url, PostBody::Form(fields)).await?;
131
132 Ok(serde_json::from_slice(&bytes)?)
133 }
134
135 async fn modify_token(
136 &self,
137 action: &str,
138 token: &Token,
139 columns: &[&str],
140 ) -> Result<(Response, bool)> {
141 let mut token = token.clone();
142 token.owner = get_owner(&token.owner, "admin");
143
144 let id = format!("{}/{}", token.owner, token.name);
145 self.modify_object(action, &id, &token, columns).await
146 }
147}