2424//! # use google_cloud_auth::credentials::idtoken;
2525//! # use std::time::Duration;
2626//! let audience = "https://my-service.a.run.app";
27- //! let verifier = idtoken::verifier::Builder::new(audience).build();
27+ //! let verifier = idtoken::verifier::Builder::new([ audience] ).build();
2828//!
2929//! async fn verify_my_token(token: &str) -> anyhow::Result<()> {
3030//! let claims = verifier.verify(token).await?;
@@ -43,21 +43,29 @@ use std::time::Duration;
4343
4444/// Builder is used construct a [Verifier] of id tokens.
4545pub struct Builder {
46- audience : String ,
46+ audiences : Vec < String > ,
4747 email : Option < String > ,
4848 jwks_url : Option < String > ,
4949 clock_skew : Option < Duration > ,
5050}
5151
5252impl Builder {
53- /// Create a [Verifier] for ID Tokens with a target audience
54- /// for the token verification.
55- pub fn new < S : Into < String > > ( audience : S ) -> Self {
53+ /// Create a [Verifier] for ID Tokens with a list of target
54+ /// audiences for the token verification.
55+ pub fn new < I , S > ( audiences : I ) -> Self
56+ where
57+ I : IntoIterator < Item = S > ,
58+ S : Into < String > ,
59+ {
60+ let audiences = audiences
61+ . into_iter ( )
62+ . map ( |s| s. into ( ) )
63+ . collect :: < Vec < String > > ( ) ;
5664 Self {
57- audience : audience. into ( ) ,
58- clock_skew : None ,
65+ audiences,
5966 email : None ,
6067 jwks_url : None ,
68+ clock_skew : None ,
6169 }
6270 }
6371
@@ -70,8 +78,7 @@ impl Builder {
7078 ///
7179 /// ```
7280 /// # use google_cloud_auth::credentials::idtoken::verifier::Builder;
73- /// let audience = "https://example.com";
74- /// let verifier = Builder::new(audience)
81+ /// let verifier = Builder::new(["https://my-service.a.run.app"])
7582 /// .with_email("[email protected] ") 7683 /// .build();
7784 /// ```
@@ -89,8 +96,7 @@ impl Builder {
8996 ///
9097 /// ```
9198 /// # use google_cloud_auth::credentials::idtoken::verifier::Builder;
92- /// let audience = "https://example.com";
93- /// let verifier = Builder::new(audience)
99+ /// let verifier = Builder::new(["https://my-service.a.run.app"])
94100 /// .with_jwks_url("https://www.googleapis.com/oauth2/v3/certs")
95101 /// .build();
96102 /// ```
@@ -109,8 +115,7 @@ impl Builder {
109115 /// ```
110116 /// # use google_cloud_auth::credentials::idtoken::Builder;
111117 /// # use std::time::Duration;
112- /// let audience = "https://example.com";
113- /// let verifier = Builder::new(audience)
118+ /// let verifier = Builder::new(["https://my-service.a.run.app"])
114119 /// .with_clock_skew(Duration::from_secs(60))
115120 /// .build();
116121 /// ```
@@ -123,7 +128,7 @@ impl Builder {
123128 pub fn build ( self ) -> Verifier {
124129 Verifier {
125130 jwk_client : JwkClient :: new ( ) ,
126- audience : self . audience . clone ( ) ,
131+ audiences : self . audiences . clone ( ) ,
127132 email : self . email . clone ( ) ,
128133 jwks_url : self . jwks_url . clone ( ) ,
129134 clock_skew : self . clock_skew . unwrap_or_else ( || Duration :: from_secs ( 10 ) ) ,
@@ -140,8 +145,7 @@ impl Builder {
140145/// # use std::time::Duration;
141146///
142147/// async fn verify_id_token(token: &str) {
143- /// let audience = "https://example.com";
144- /// let verifier = Builder::new(audience).build();
148+ /// let verifier = Builder::new(["https://my-service.a.run.app"]).build();
145149///
146150/// let claims = verifier.verify(token).await.expect("Failed to verify ID token");
147151/// println!("Verified claims: {:?}", claims);
@@ -150,7 +154,7 @@ impl Builder {
150154#[ derive( Debug ) ]
151155pub struct Verifier {
152156 jwk_client : JwkClient ,
153- audience : String ,
157+ audiences : Vec < String > ,
154158 email : Option < String > ,
155159 jwks_url : Option < String > ,
156160 clock_skew : Duration ,
@@ -169,7 +173,7 @@ impl Verifier {
169173 validation. leeway = self . clock_skew . as_secs ( ) ;
170174 // TODO(#3591): Support TPC/REP that can have different issuers
171175 validation. set_issuer ( & [ "https://accounts.google.com" , "accounts.google.com" ] ) ;
172- validation. set_audience ( std :: slice :: from_ref ( & self . audience ) ) ;
176+ validation. set_audience ( & self . audiences ) ;
173177
174178 let expected_email = self . email . clone ( ) ;
175179 let jwks_url = self . jwks_url . clone ( ) ;
@@ -338,7 +342,7 @@ pub(crate) mod tests {
338342 let token = generate_test_id_token ( audience) ;
339343 let token = token. as_str ( ) ;
340344
341- let verifier = Builder :: new ( audience)
345+ let verifier = Builder :: new ( [ audience] )
342346 . with_jwks_url ( format ! ( "http://{}/certs" , server. addr( ) ) )
343347 . build ( ) ;
344348
@@ -364,7 +368,7 @@ pub(crate) mod tests {
364368 let token = generate_test_id_token ( audience) ;
365369 let token = token. as_str ( ) ;
366370
367- let verifier = Builder :: new ( "https://wrong-audience.com" )
371+ let verifier = Builder :: new ( [ "https://wrong-audience.com" ] )
368372 . with_jwks_url ( format ! ( "http://{}/certs" , server. addr( ) ) )
369373 . build ( ) ;
370374
@@ -375,6 +379,30 @@ pub(crate) mod tests {
375379 Ok ( ( ) )
376380 }
377381
382+ #[ tokio:: test]
383+ async fn test_verify_multiple_audience_success ( ) -> TestResult {
384+ let server = Server :: run ( ) ;
385+ server. expect (
386+ Expectation :: matching ( all_of ! [ request:: path( "/certs" ) , ] )
387+ . times ( 1 )
388+ . respond_with ( json_encoded ( create_jwk_set_response ( ) ) ) ,
389+ ) ;
390+
391+ let audiences = [ "https://example.com" , "https://another_example.com" ] ;
392+ let verifier = Builder :: new ( audiences)
393+ . with_jwks_url ( format ! ( "http://{}/certs" , server. addr( ) ) )
394+ . build ( ) ;
395+
396+ for audience in audiences {
397+ let token = generate_test_id_token ( audience) ;
398+ let token = token. as_str ( ) ;
399+ let claims = verifier. verify ( token) . await ?;
400+ assert ! ( !claims. is_empty( ) ) ;
401+ }
402+
403+ Ok ( ( ) )
404+ }
405+
378406 #[ tokio:: test]
379407 async fn test_verify_invalid_issuer ( ) -> TestResult {
380408 let server = Server :: run ( ) ;
@@ -390,7 +418,7 @@ pub(crate) mod tests {
390418 let token = generate_test_id_token_with_claims ( audience, claims) ;
391419 let token = token. as_str ( ) ;
392420
393- let verifier = Builder :: new ( audience)
421+ let verifier = Builder :: new ( [ audience] )
394422 . with_jwks_url ( format ! ( "http://{}/certs" , server. addr( ) ) )
395423 . build ( ) ;
396424
@@ -418,7 +446,7 @@ pub(crate) mod tests {
418446 let token = generate_test_id_token_with_claims ( audience, claims) ;
419447 let token = token. as_str ( ) ;
420448
421- let verifier = Builder :: new ( audience)
449+ let verifier = Builder :: new ( [ audience] )
422450 . with_jwks_url ( format ! ( "http://{}/certs" , server. addr( ) ) )
423451 . with_email ( email)
424452 . build ( ) ;
@@ -448,7 +476,7 @@ pub(crate) mod tests {
448476 let token = generate_test_id_token_with_claims ( audience, claims) ;
449477 let token = token. as_str ( ) ;
450478
451- let verifier = Builder :: new ( audience)
479+ let verifier = Builder :: new ( [ audience] )
452480 . with_jwks_url ( format ! ( "http://{}/certs" , server. addr( ) ) )
453481454482 . build ( ) ;
@@ -475,7 +503,7 @@ pub(crate) mod tests {
475503 let token = generate_test_id_token_with_claims ( audience, claims) ;
476504 let token = token. as_str ( ) ;
477505
478- let verifier = Builder :: new ( audience)
506+ let verifier = Builder :: new ( [ audience] )
479507 . with_jwks_url ( format ! ( "http://{}/certs" , server. addr( ) ) )
480508 . build ( ) ;
481509
@@ -503,7 +531,7 @@ pub(crate) mod tests {
503531 let token = generate_test_id_token_with_claims ( audience, claims) ;
504532 let token = token. as_str ( ) ;
505533
506- let verifier = Builder :: new ( audience)
534+ let verifier = Builder :: new ( [ audience] )
507535 . with_jwks_url ( format ! ( "http://{}/certs" , server. addr( ) ) )
508536 . with_email ( email)
509537 . build ( ) ;
@@ -530,7 +558,7 @@ pub(crate) mod tests {
530558 let token = generate_test_id_token_with_claims ( audience, claims) ;
531559 let token = token. as_str ( ) ;
532560
533- let verifier = Builder :: new ( audience)
561+ let verifier = Builder :: new ( [ audience] )
534562 . with_jwks_url ( format ! ( "http://{}/certs" , server. addr( ) ) )
535563 . with_clock_skew ( Duration :: from_secs ( 10 ) )
536564 . build ( ) ;
@@ -544,7 +572,7 @@ pub(crate) mod tests {
544572 #[ tokio:: test]
545573 async fn test_verify_decode_error ( ) -> TestResult {
546574 let audience = "https://example.com" ;
547- let verifier = Builder :: new ( audience) . build ( ) ;
575+ let verifier = Builder :: new ( [ audience] ) . build ( ) ;
548576 let invalid_token = "invalid.token.format" ;
549577
550578 let result = verifier. verify ( invalid_token) . await ;
@@ -568,7 +596,7 @@ pub(crate) mod tests {
568596 let token =
569597 jsonwebtoken:: encode ( & header, & claims, & private_key) . expect ( "failed to encode jwt" ) ;
570598
571- let verifier = Builder :: new ( "https://example.com" ) . build ( ) ;
599+ let verifier = Builder :: new ( [ "https://example.com" ] ) . build ( ) ;
572600
573601 let result = verifier. verify ( & token) . await ;
574602 assert ! ( result. is_err( ) ) ;
@@ -590,7 +618,7 @@ pub(crate) mod tests {
590618 let token = generate_test_id_token ( audience) ;
591619 let token = token. as_str ( ) ;
592620
593- let verifier = Builder :: new ( audience)
621+ let verifier = Builder :: new ( [ audience] )
594622 . with_jwks_url ( format ! ( "http://{}/certs" , server. addr( ) ) )
595623 . build ( ) ;
596624
0 commit comments