@@ -23,6 +23,7 @@ public class FirebaseSender : IFirebaseSender
2323 private readonly HttpClient http ;
2424 private readonly FirebaseSettings settings ;
2525 private readonly IJsonSerializer serializer ;
26+ private readonly SemaphoreSlim tokenLock = new ( 1 , 1 ) ;
2627
2728 private DateTime ? firebaseTokenExpiration ;
2829 private FirebaseTokenResponse firebaseToken ;
@@ -121,30 +122,43 @@ private async Task<string> GetJwtTokenAsync(CancellationToken cancellationToken)
121122 return firebaseToken . AccessToken ;
122123 }
123124
124- using var message = new HttpRequestMessage ( HttpMethod . Post , "https://oauth2.googleapis.com/token" ) ;
125- using var form = new MultipartFormDataContent ( ) ;
126- var authToken = GetMasterToken ( ) ;
127- form . Add ( new StringContent ( authToken ) , "assertion" ) ;
128- form . Add ( new StringContent ( "urn:ietf:params:oauth:grant-type:jwt-bearer" ) , "grant_type" ) ;
129- message . Content = form ;
130-
131- using var response = await http . SendAsync ( message , cancellationToken ) ;
132- var content = await response . Content . ReadAsStringAsync ( cancellationToken ) ;
133-
134- if ( ! response . IsSuccessStatusCode )
125+ await tokenLock . WaitAsync ( cancellationToken ) ;
126+ try
135127 {
136- throw new HttpRequestException ( "Firebase error when creating JWT token: " + content ) ;
137- }
128+ if ( firebaseToken != null && firebaseTokenExpiration > DateTime . UtcNow )
129+ {
130+ return firebaseToken . AccessToken ;
131+ }
132+
133+ using var message = new HttpRequestMessage ( HttpMethod . Post , "https://oauth2.googleapis.com/token" ) ;
134+ using var form = new MultipartFormDataContent ( ) ;
135+ var authToken = GetMasterToken ( ) ;
136+ form . Add ( new StringContent ( authToken ) , "assertion" ) ;
137+ form . Add ( new StringContent ( "urn:ietf:params:oauth:grant-type:jwt-bearer" ) , "grant_type" ) ;
138+ message . Content = form ;
139+
140+ using var response = await http . SendAsync ( message , cancellationToken ) ;
141+ var content = await response . Content . ReadAsStringAsync ( cancellationToken ) ;
142+
143+ if ( ! response . IsSuccessStatusCode )
144+ {
145+ throw new HttpRequestException ( "Firebase error when creating JWT token: " + content ) ;
146+ }
147+
148+ firebaseToken = serializer . Deserialize < FirebaseTokenResponse > ( content ) ;
149+ firebaseTokenExpiration = DateTime . UtcNow . AddSeconds ( firebaseToken . ExpiresIn - 10 ) ;
150+
151+ if ( string . IsNullOrWhiteSpace ( firebaseToken . AccessToken ) || firebaseTokenExpiration < DateTime . UtcNow )
152+ {
153+ throw new InvalidOperationException ( "Couldn't deserialize firebase token response" ) ;
154+ }
138155
139- firebaseToken = serializer . Deserialize < FirebaseTokenResponse > ( content ) ;
140- firebaseTokenExpiration = DateTime . UtcNow . AddSeconds ( firebaseToken . ExpiresIn - 10 ) ;
141-
142- if ( string . IsNullOrWhiteSpace ( firebaseToken . AccessToken ) || firebaseTokenExpiration < DateTime . UtcNow )
156+ return firebaseToken . AccessToken ;
157+ }
158+ finally
143159 {
144- throw new InvalidOperationException ( "Couldn't deserialize firebase token response" ) ;
160+ tokenLock . Release ( ) ;
145161 }
146-
147- return firebaseToken . AccessToken ;
148162 }
149163
150164 private string GetMasterToken ( )
0 commit comments