@@ -102,7 +102,7 @@ public async Task<PushResult> SendAsync(object payload, CancellationToken cancel
102102 HttpMethod . Post ,
103103 $ "https://fcm.googleapis.com/v1/projects/{ settings . ProjectId } /messages:send") ;
104104
105- var token = await GetJwtTokenAsync ( ) ;
105+ var token = await GetJwtTokenAsync ( cancellationToken ) ;
106106
107107 message . Headers . Add ( "Authorization" , $ "Bearer { token } ") ;
108108 message . Content = new StringContent ( json , Encoding . UTF8 , "application/json" ) ;
@@ -118,22 +118,22 @@ public async Task<PushResult> SendAsync(object payload, CancellationToken cancel
118118 firebaseResponse . Error ? . Status ) ;
119119 }
120120
121- private async Task < string > GetJwtTokenAsync ( )
121+ private async Task < string > GetJwtTokenAsync ( CancellationToken cancellationToken )
122122 {
123123 if ( firebaseToken != null && firebaseTokenExpiration > DateTime . UtcNow )
124124 {
125125 return firebaseToken . AccessToken ;
126126 }
127-
127+
128128 using var message = new HttpRequestMessage ( HttpMethod . Post , "https://oauth2.googleapis.com/token" ) ;
129129 using var form = new MultipartFormDataContent ( ) ;
130130 var authToken = GetMasterToken ( ) ;
131131 form . Add ( new StringContent ( authToken ) , "assertion" ) ;
132132 form . Add ( new StringContent ( "urn:ietf:params:oauth:grant-type:jwt-bearer" ) , "grant_type" ) ;
133133 message . Content = form ;
134134
135- using var response = await http . SendAsync ( message ) ;
136- var content = await response . Content . ReadAsStringAsync ( ) ;
135+ using var response = await http . SendAsync ( message , cancellationToken ) ;
136+ var content = await response . Content . ReadAsStringAsync ( cancellationToken ) ;
137137
138138 if ( ! response . IsSuccessStatusCode )
139139 {
@@ -163,8 +163,8 @@ private string GetMasterToken()
163163 exp = CryptoHelper . GetEpochTimestamp ( ) + 3600 /* has to be short lived */
164164 } ) ;
165165
166- var headerBase64 = Convert . ToBase64String ( Encoding . UTF8 . GetBytes ( header ) ) ;
167- var payloadBase64 = Convert . ToBase64String ( Encoding . UTF8 . GetBytes ( payload ) ) ;
166+ var headerBase64 = Base64UrlEncode ( Encoding . UTF8 . GetBytes ( header ) ) ;
167+ var payloadBase64 = Base64UrlEncode ( Encoding . UTF8 . GetBytes ( payload ) ) ;
168168 var unsignedJwtData = $ "{ headerBase64 } .{ payloadBase64 } ";
169169 var unsignedJwtBytes = Encoding . UTF8 . GetBytes ( unsignedJwtData ) ;
170170
@@ -174,11 +174,17 @@ private string GetMasterToken()
174174 signer . BlockUpdate ( unsignedJwtBytes , 0 , unsignedJwtBytes . Length ) ;
175175
176176 var signature = signer . GenerateSignature ( ) ;
177- var signatureBase64 = Convert . ToBase64String ( signature ) ;
177+ var signatureBase64 = Base64UrlEncode ( signature ) ;
178178
179179 return $ "{ unsignedJwtData } .{ signatureBase64 } ";
180180 }
181181
182+ private static string Base64UrlEncode ( byte [ ] bytes ) =>
183+ Convert . ToBase64String ( bytes )
184+ . Replace ( '+' , '-' )
185+ . Replace ( '/' , '_' )
186+ . TrimEnd ( '=' ) ;
187+
182188 private static AsymmetricKeyParameter ParsePkcs8PrivateKeyPem ( string key )
183189 {
184190 using var keyReader = new StringReader ( key ) ;
0 commit comments