@@ -7,8 +7,12 @@ use openidconnect::{
7
7
} ;
8
8
9
9
use reqwest:: header:: { HeaderMap , ACCEPT , AUTHORIZATION , CONTENT_TYPE } ;
10
+ use serde:: de:: DeserializeOwned ;
10
11
use serde:: { Deserialize , Serialize } ;
12
+ use std:: cmp:: Eq ;
11
13
use std:: collections:: HashMap ;
14
+ use std:: fmt:: Debug ;
15
+ use std:: hash:: Hash ;
12
16
13
17
use crate :: credentials:: { Application , ApplicationError } ;
14
18
@@ -36,7 +40,10 @@ custom_error! {
36
40
/// - When scope contains `urn:zitadel:iam:user:metadata`, the metadata hashmap will be
37
41
/// filled with the user metadata.
38
42
#[ derive( Clone , Debug , Serialize , Deserialize , Default ) ]
39
- pub struct ZitadelIntrospectionExtraTokenFields {
43
+ pub struct ZitadelIntrospectionExtraTokenFields < Role = String >
44
+ where
45
+ Role : Hash + Eq + Clone ,
46
+ {
40
47
pub name : Option < String > ,
41
48
pub given_name : Option < String > ,
42
49
pub family_name : Option < String > ,
@@ -50,15 +57,20 @@ pub struct ZitadelIntrospectionExtraTokenFields {
50
57
pub resource_owner_name : Option < String > ,
51
58
#[ serde( rename = "urn:zitadel:iam:user:resourceowner:primary_domain" ) ]
52
59
pub resource_owner_primary_domain : Option < String > ,
60
+ #[ serde( rename = "urn:zitadel:iam:org:project:roles" ) ]
61
+ pub project_roles : Option < HashMap < Role , HashMap < String , String > > > ,
53
62
#[ serde( rename = "urn:zitadel:iam:user:metadata" ) ]
54
63
pub metadata : Option < HashMap < String , String > > ,
55
64
}
56
65
57
- impl ExtraTokenFields for ZitadelIntrospectionExtraTokenFields { }
66
+ impl < Role : Debug + Hash + Eq + DeserializeOwned + Serialize + Clone > ExtraTokenFields
67
+ for ZitadelIntrospectionExtraTokenFields < Role >
68
+ {
69
+ }
58
70
59
71
/// Type alias for the ZITADEL introspection response.
60
- pub type ZitadelIntrospectionResponse =
61
- StandardTokenIntrospectionResponse < ZitadelIntrospectionExtraTokenFields , CoreTokenType > ;
72
+ pub type ZitadelIntrospectionResponse < Role = String > =
73
+ StandardTokenIntrospectionResponse < ZitadelIntrospectionExtraTokenFields < Role > , CoreTokenType > ;
62
74
63
75
/// Definition of the authentication scheme against the authority (or issuer). This authentication
64
76
/// is required when performing actions like introspection against any ZITADEL instance.
@@ -163,7 +175,7 @@ fn payload(
163
175
/// let token = "dEnGhIFs3VnqcQU5D2zRSeiarB1nwH6goIKY0J8MWZbsnWcTuu1C59lW9DgCq1y096GYdXA";
164
176
/// let metadata = discover(authority).await?;
165
177
///
166
- /// let result = introspect(
178
+ /// let result = introspect::<String> (
167
179
/// metadata.additional_metadata().introspection_endpoint.as_ref().unwrap(),
168
180
/// authority,
169
181
/// &auth,
@@ -174,12 +186,12 @@ fn payload(
174
186
/// # Ok(())
175
187
/// # }
176
188
/// ```
177
- pub async fn introspect (
189
+ pub async fn introspect < Role : Hash + Debug + Eq + DeserializeOwned + Serialize + Clone > (
178
190
introspection_uri : & str ,
179
191
authority : & str ,
180
192
authentication : & AuthorityAuthentication ,
181
193
token : & str ,
182
- ) -> Result < ZitadelIntrospectionResponse , IntrospectionError > {
194
+ ) -> Result < ZitadelIntrospectionResponse < Role > , IntrospectionError > {
183
195
let response = async_http_client ( HttpRequest {
184
196
url : Url :: parse ( introspection_uri)
185
197
. map_err ( |source| IntrospectionError :: ParseUrl { source } ) ?,
@@ -190,17 +202,19 @@ pub async fn introspect(
190
202
. await
191
203
. map_err ( |source| IntrospectionError :: RequestFailed { source } ) ?;
192
204
193
- let mut response: ZitadelIntrospectionResponse =
205
+ let mut response: ZitadelIntrospectionResponse < Role > =
194
206
serde_json:: from_slice ( response. body . as_slice ( ) )
195
207
. map_err ( |source| IntrospectionError :: ParseResponse { source } ) ?;
196
- decode_metadata ( & mut response) ?;
208
+ decode_metadata :: < Role > ( & mut response) ?;
197
209
Ok ( response)
198
210
}
199
211
200
212
// Metadata values are base64 encoded.
201
- fn decode_metadata ( response : & mut ZitadelIntrospectionResponse ) -> Result < ( ) , IntrospectionError > {
213
+ fn decode_metadata < Role : Hash + Debug + Eq + DeserializeOwned + Serialize + Clone > (
214
+ response : & mut ZitadelIntrospectionResponse < Role > ,
215
+ ) -> Result < ( ) , IntrospectionError > {
202
216
if let Some ( h) = & response. extra_fields ( ) . metadata {
203
- let mut extra = response. extra_fields ( ) . clone ( ) ;
217
+ let mut extra: ZitadelIntrospectionExtraTokenFields < Role > = response. extra_fields ( ) . clone ( ) ;
204
218
let mut metadata = HashMap :: new ( ) ;
205
219
for ( k, v) in h {
206
220
let decoded_v = base64:: decode ( v)
@@ -229,7 +243,7 @@ mod tests {
229
243
230
244
#[ tokio:: test]
231
245
async fn introspect_fails_with_invalid_url ( ) {
232
- let result = introspect (
246
+ let result = introspect :: < String > (
233
247
"foobar" ,
234
248
"foobar" ,
235
249
& AuthorityAuthentication :: Basic {
@@ -250,7 +264,7 @@ mod tests {
250
264
#[ tokio:: test]
251
265
async fn introspect_fails_with_invalid_endpoint ( ) {
252
266
let meta = discover ( ZITADEL_URL ) . await . unwrap ( ) ;
253
- let result = introspect (
267
+ let result = introspect :: < String > (
254
268
& meta. token_endpoint ( ) . unwrap ( ) . to_string ( ) ,
255
269
ZITADEL_URL ,
256
270
& AuthorityAuthentication :: Basic {
@@ -267,7 +281,7 @@ mod tests {
267
281
#[ tokio:: test]
268
282
async fn introspect_succeeds ( ) {
269
283
let meta = discover ( ZITADEL_URL ) . await . unwrap ( ) ;
270
- let result = introspect (
284
+ let result = introspect :: < String > (
271
285
& meta
272
286
. additional_metadata ( )
273
287
. introspection_endpoint
0 commit comments