/// <inheritdoc /> public async Task <OAuth2Token> FetchToken(CancellationToken ct = default) { var token = await tokenStorage.GetTokeAsync().ConfigureAwait(false); if (token == null) { logger.LogTrace("No stored token found."); return(null); } if (!token.IsExpired) { logger.LogTrace("Existing token returned."); return(token); } try { semaphore.Wait(ct); logger.LogTrace("Try refresh token."); token = await authenticator.RefreshTokenAsync(token, ct) .ConfigureAwait(false); await tokenStorage.AddTokenAsync(token).ConfigureAwait(false); return(token); } catch (Exception exception) { logger.LogError("Failed refresh token: {Message}", exception.Message); await tokenStorage.AddTokenAsync(null).ConfigureAwait(false); return(null); } finally { semaphore.Release(); } }