gemini_adk_rs/auth/
schemes.rs1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "snake_case")]
9pub enum OAuthGrantType {
10 ClientCredentials,
12 AuthorizationCode,
14 Implicit,
16 Password,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22#[serde(tag = "type")]
23pub enum AuthScheme {
24 #[serde(rename = "apiKey")]
26 ApiKey {
27 #[serde(rename = "in")]
29 location: String,
30 name: String,
32 },
33 #[serde(rename = "http")]
35 Http {
36 scheme: String,
38 #[serde(skip_serializing_if = "Option::is_none")]
40 bearer_format: Option<String>,
41 },
42 #[serde(rename = "oauth2")]
44 OAuth2 {
45 #[serde(skip_serializing_if = "Option::is_none")]
47 grant_type: Option<OAuthGrantType>,
48 #[serde(skip_serializing_if = "Option::is_none")]
50 authorization_url: Option<String>,
51 #[serde(skip_serializing_if = "Option::is_none")]
53 token_url: Option<String>,
54 #[serde(skip_serializing_if = "Option::is_none")]
56 scopes: Option<HashMap<String, String>>,
57 },
58 #[serde(rename = "openIdConnect")]
60 OpenIdConnect {
61 open_id_connect_url: String,
63 },
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn oauth_grant_type_snake_case() {
72 assert_eq!(
73 serde_json::to_string(&OAuthGrantType::ClientCredentials).unwrap(),
74 "\"client_credentials\""
75 );
76 assert_eq!(
77 serde_json::to_string(&OAuthGrantType::AuthorizationCode).unwrap(),
78 "\"authorization_code\""
79 );
80 assert_eq!(
81 serde_json::to_string(&OAuthGrantType::Implicit).unwrap(),
82 "\"implicit\""
83 );
84 assert_eq!(
85 serde_json::to_string(&OAuthGrantType::Password).unwrap(),
86 "\"password\""
87 );
88 }
89
90 #[test]
91 fn oauth_grant_type_roundtrip() {
92 let types = [
93 OAuthGrantType::ClientCredentials,
94 OAuthGrantType::AuthorizationCode,
95 OAuthGrantType::Implicit,
96 OAuthGrantType::Password,
97 ];
98 for t in &types {
99 let json = serde_json::to_string(t).unwrap();
100 let parsed: OAuthGrantType = serde_json::from_str(&json).unwrap();
101 assert_eq!(&parsed, t);
102 }
103 }
104
105 #[test]
106 fn api_key_scheme_tagged_serialization() {
107 let scheme = AuthScheme::ApiKey {
108 location: "header".into(),
109 name: "X-API-Key".into(),
110 };
111
112 let json = serde_json::to_value(&scheme).unwrap();
113 assert_eq!(json["type"], "apiKey");
114 assert_eq!(json["in"], "header");
115 assert_eq!(json["name"], "X-API-Key");
116
117 let parsed: AuthScheme = serde_json::from_value(json).unwrap();
119 match parsed {
120 AuthScheme::ApiKey { location, name } => {
121 assert_eq!(location, "header");
122 assert_eq!(name, "X-API-Key");
123 }
124 _ => panic!("expected ApiKey variant"),
125 }
126 }
127
128 #[test]
129 fn http_scheme_tagged_serialization() {
130 let scheme = AuthScheme::Http {
131 scheme: "bearer".into(),
132 bearer_format: Some("JWT".into()),
133 };
134
135 let json = serde_json::to_value(&scheme).unwrap();
136 assert_eq!(json["type"], "http");
137 assert_eq!(json["scheme"], "bearer");
138 assert_eq!(json["bearer_format"], "JWT");
139
140 let parsed: AuthScheme = serde_json::from_value(json).unwrap();
141 match parsed {
142 AuthScheme::Http {
143 scheme,
144 bearer_format,
145 } => {
146 assert_eq!(scheme, "bearer");
147 assert_eq!(bearer_format.as_deref(), Some("JWT"));
148 }
149 _ => panic!("expected Http variant"),
150 }
151 }
152
153 #[test]
154 fn http_scheme_omits_none_bearer_format() {
155 let scheme = AuthScheme::Http {
156 scheme: "basic".into(),
157 bearer_format: None,
158 };
159
160 let json = serde_json::to_value(&scheme).unwrap();
161 assert_eq!(json["type"], "http");
162 assert_eq!(json["scheme"], "basic");
163 assert!(json.get("bearer_format").is_none());
164 }
165
166 #[test]
167 fn oauth2_scheme_tagged_serialization() {
168 let mut scopes = HashMap::new();
169 scopes.insert("read".into(), "Read access".into());
170 scopes.insert("write".into(), "Write access".into());
171
172 let scheme = AuthScheme::OAuth2 {
173 grant_type: Some(OAuthGrantType::AuthorizationCode),
174 authorization_url: Some("https://example.com/authorize".into()),
175 token_url: Some("https://example.com/token".into()),
176 scopes: Some(scopes),
177 };
178
179 let json = serde_json::to_value(&scheme).unwrap();
180 assert_eq!(json["type"], "oauth2");
181 assert_eq!(json["grant_type"], "authorization_code");
182 assert_eq!(json["authorization_url"], "https://example.com/authorize");
183
184 let parsed: AuthScheme = serde_json::from_value(json).unwrap();
185 match parsed {
186 AuthScheme::OAuth2 {
187 grant_type, scopes, ..
188 } => {
189 assert_eq!(grant_type, Some(OAuthGrantType::AuthorizationCode));
190 assert_eq!(scopes.as_ref().unwrap().len(), 2);
191 }
192 _ => panic!("expected OAuth2 variant"),
193 }
194 }
195
196 #[test]
197 fn oauth2_scheme_omits_none_fields() {
198 let scheme = AuthScheme::OAuth2 {
199 grant_type: None,
200 authorization_url: None,
201 token_url: None,
202 scopes: None,
203 };
204
205 let json = serde_json::to_value(&scheme).unwrap();
206 assert_eq!(json["type"], "oauth2");
207 assert!(json.get("grant_type").is_none());
209 assert!(json.get("authorization_url").is_none());
210 assert!(json.get("token_url").is_none());
211 assert!(json.get("scopes").is_none());
212 }
213
214 #[test]
215 fn openid_connect_scheme_tagged_serialization() {
216 let scheme = AuthScheme::OpenIdConnect {
217 open_id_connect_url: "https://example.com/.well-known/openid-configuration".into(),
218 };
219
220 let json = serde_json::to_value(&scheme).unwrap();
221 assert_eq!(json["type"], "openIdConnect");
222 assert_eq!(
223 json["open_id_connect_url"],
224 "https://example.com/.well-known/openid-configuration"
225 );
226
227 let parsed: AuthScheme = serde_json::from_value(json).unwrap();
228 match parsed {
229 AuthScheme::OpenIdConnect {
230 open_id_connect_url,
231 } => {
232 assert_eq!(
233 open_id_connect_url,
234 "https://example.com/.well-known/openid-configuration"
235 );
236 }
237 _ => panic!("expected OpenIdConnect variant"),
238 }
239 }
240}