@@ -7,8 +7,12 @@ use openidconnect::{
77} ;
88
99use reqwest:: header:: { HeaderMap , ACCEPT , AUTHORIZATION , CONTENT_TYPE } ;
10+ use serde:: de:: DeserializeOwned ;
1011use serde:: { Deserialize , Serialize } ;
12+ use std:: cmp:: Eq ;
1113use std:: collections:: HashMap ;
14+ use std:: fmt:: Debug ;
15+ use std:: hash:: Hash ;
1216
1317use crate :: credentials:: { Application , ApplicationError } ;
1418
@@ -36,7 +40,10 @@ custom_error! {
3640/// - When scope contains `urn:zitadel:iam:user:metadata`, the metadata hashmap will be
3741/// filled with the user metadata.
3842#[ derive( Clone , Debug , Serialize , Deserialize , Default ) ]
39- pub struct ZitadelIntrospectionExtraTokenFields {
43+ pub struct ZitadelIntrospectionExtraTokenFields < Role = String >
44+ where
45+ Role : Hash + Eq + Clone ,
46+ {
4047 pub name : Option < String > ,
4148 pub given_name : Option < String > ,
4249 pub family_name : Option < String > ,
@@ -50,15 +57,20 @@ pub struct ZitadelIntrospectionExtraTokenFields {
5057 pub resource_owner_name : Option < String > ,
5158 #[ serde( rename = "urn:zitadel:iam:user:resourceowner:primary_domain" ) ]
5259 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 > > > ,
5362 #[ serde( rename = "urn:zitadel:iam:user:metadata" ) ]
5463 pub metadata : Option < HashMap < String , String > > ,
5564}
5665
57- impl ExtraTokenFields for ZitadelIntrospectionExtraTokenFields { }
66+ impl < Role : Debug + Hash + Eq + DeserializeOwned + Serialize + Clone > ExtraTokenFields
67+ for ZitadelIntrospectionExtraTokenFields < Role >
68+ {
69+ }
5870
5971/// 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 > ;
6274
6375/// Definition of the authentication scheme against the authority (or issuer). This authentication
6476/// is required when performing actions like introspection against any ZITADEL instance.
@@ -163,7 +175,7 @@ fn payload(
163175/// let token = "dEnGhIFs3VnqcQU5D2zRSeiarB1nwH6goIKY0J8MWZbsnWcTuu1C59lW9DgCq1y096GYdXA";
164176/// let metadata = discover(authority).await?;
165177///
166- /// let result = introspect(
178+ /// let result = introspect::<String> (
167179/// metadata.additional_metadata().introspection_endpoint.as_ref().unwrap(),
168180/// authority,
169181/// &auth,
@@ -174,12 +186,12 @@ fn payload(
174186/// # Ok(())
175187/// # }
176188/// ```
177- pub async fn introspect (
189+ pub async fn introspect < Role : Hash + Debug + Eq + DeserializeOwned + Serialize + Clone > (
178190 introspection_uri : & str ,
179191 authority : & str ,
180192 authentication : & AuthorityAuthentication ,
181193 token : & str ,
182- ) -> Result < ZitadelIntrospectionResponse , IntrospectionError > {
194+ ) -> Result < ZitadelIntrospectionResponse < Role > , IntrospectionError > {
183195 let response = async_http_client ( HttpRequest {
184196 url : Url :: parse ( introspection_uri)
185197 . map_err ( |source| IntrospectionError :: ParseUrl { source } ) ?,
@@ -190,17 +202,19 @@ pub async fn introspect(
190202 . await
191203 . map_err ( |source| IntrospectionError :: RequestFailed { source } ) ?;
192204
193- let mut response: ZitadelIntrospectionResponse =
205+ let mut response: ZitadelIntrospectionResponse < Role > =
194206 serde_json:: from_slice ( response. body . as_slice ( ) )
195207 . map_err ( |source| IntrospectionError :: ParseResponse { source } ) ?;
196- decode_metadata ( & mut response) ?;
208+ decode_metadata :: < Role > ( & mut response) ?;
197209 Ok ( response)
198210}
199211
200212// 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 > {
202216 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 ( ) ;
204218 let mut metadata = HashMap :: new ( ) ;
205219 for ( k, v) in h {
206220 let decoded_v = base64:: decode ( v)
@@ -229,7 +243,7 @@ mod tests {
229243
230244 #[ tokio:: test]
231245 async fn introspect_fails_with_invalid_url ( ) {
232- let result = introspect (
246+ let result = introspect :: < String > (
233247 "foobar" ,
234248 "foobar" ,
235249 & AuthorityAuthentication :: Basic {
@@ -250,7 +264,7 @@ mod tests {
250264 #[ tokio:: test]
251265 async fn introspect_fails_with_invalid_endpoint ( ) {
252266 let meta = discover ( ZITADEL_URL ) . await . unwrap ( ) ;
253- let result = introspect (
267+ let result = introspect :: < String > (
254268 & meta. token_endpoint ( ) . unwrap ( ) . to_string ( ) ,
255269 ZITADEL_URL ,
256270 & AuthorityAuthentication :: Basic {
@@ -267,7 +281,7 @@ mod tests {
267281 #[ tokio:: test]
268282 async fn introspect_succeeds ( ) {
269283 let meta = discover ( ZITADEL_URL ) . await . unwrap ( ) ;
270- let result = introspect (
284+ let result = introspect :: < String > (
271285 & meta
272286 . additional_metadata ( )
273287 . introspection_endpoint
0 commit comments