@@ -4,6 +4,8 @@ use std::path::{Path, PathBuf};
44use std:: sync:: RwLock ;
55
66use async_trait:: async_trait;
7+ use base64:: { engine:: general_purpose:: URL_SAFE , Engine } ;
8+ use chrono:: Utc ;
79use serde:: { Deserialize , Serialize } ;
810use tracing:: { instrument, Level } ;
911
@@ -95,8 +97,6 @@ impl ServiceAccount for CustomServiceAccount {
9597
9698 #[ instrument( level = Level :: DEBUG ) ]
9799 async fn refresh_token ( & self , client : & HyperClient , scopes : & [ & str ] ) -> Result < Token , Error > {
98- use crate :: jwt:: Claims ;
99- use crate :: jwt:: GRANT_TYPE ;
100100 use hyper:: header;
101101 use url:: form_urlencoded;
102102
@@ -136,6 +136,57 @@ impl ServiceAccount for CustomServiceAccount {
136136 }
137137}
138138
139+ /// Permissions requested for a JWT.
140+ /// See https://developers.google.com/identity/protocols/OAuth2ServiceAccount#authorizingrequests.
141+ #[ derive( Serialize , Debug ) ]
142+ pub ( crate ) struct Claims < ' a > {
143+ iss : & ' a str ,
144+ aud : & ' a str ,
145+ exp : i64 ,
146+ iat : i64 ,
147+ sub : Option < & ' a str > ,
148+ scope : String ,
149+ }
150+
151+ impl < ' a > Claims < ' a > {
152+ pub ( crate ) fn new (
153+ key : & ' a ApplicationCredentials ,
154+ scopes : & [ & str ] ,
155+ sub : Option < & ' a str > ,
156+ ) -> Self {
157+ let mut scope = String :: with_capacity ( 16 ) ;
158+ for ( i, s) in scopes. iter ( ) . enumerate ( ) {
159+ if i != 0 {
160+ scope. push ( ' ' ) ;
161+ }
162+
163+ scope. push_str ( s) ;
164+ }
165+
166+ let iat = Utc :: now ( ) . timestamp ( ) ;
167+ Claims {
168+ iss : & key. client_email ,
169+ aud : & key. token_uri ,
170+ exp : iat + 3600 - 5 , // Max validity is 1h
171+ iat,
172+ sub,
173+ scope,
174+ }
175+ }
176+
177+ pub ( crate ) fn to_jwt ( & self , signer : & Signer ) -> Result < String , Error > {
178+ let mut jwt = String :: new ( ) ;
179+ URL_SAFE . encode_string ( GOOGLE_RS256_HEAD , & mut jwt) ;
180+ jwt. push ( '.' ) ;
181+ URL_SAFE . encode_string ( & serde_json:: to_string ( self ) . unwrap ( ) , & mut jwt) ;
182+
183+ let signature = signer. sign ( jwt. as_bytes ( ) ) ?;
184+ jwt. push ( '.' ) ;
185+ URL_SAFE . encode_string ( & signature, & mut jwt) ;
186+ Ok ( jwt)
187+ }
188+ }
189+
139190#[ derive( Serialize , Deserialize , Clone ) ]
140191pub ( crate ) struct ApplicationCredentials {
141192 pub ( crate ) r#type : Option < String > ,
@@ -168,5 +219,8 @@ impl fmt::Debug for ApplicationCredentials {
168219 }
169220}
170221
222+ pub ( crate ) const GRANT_TYPE : & str = "urn:ietf:params:oauth:grant-type:jwt-bearer" ;
223+ const GOOGLE_RS256_HEAD : & str = r#"{"alg":"RS256","typ":"JWT"}"# ;
224+
171225/// How many times to attempt to fetch a token from the set credentials token endpoint.
172226const RETRY_COUNT : u8 = 5 ;
0 commit comments