Skip to content

Commit

Permalink
Use optimistic synchronization in JsonWebToken.Audiences (#2243)
Browse files Browse the repository at this point in the history
I didn't see anything in Payload.TryGetValue that would require synchronization with a concurrent call to Payload.TryGetValue. And without that, and since concurrent access is not something to optimize for here, we can instead employ optimistic synchronization and just swap in the result with an interlocked. If there's a race condition and two threads do end up accessing Audiences on the same instance concurrently, they may both end up creating the array, but only one will be published for all to consume.

In addition to making Audiences cheaper to access, the primary benefit here is it saves an allocation per JsonWebToken, which no longer needs to construct the audiences lock object.
  • Loading branch information
stephentoub authored and Brent Schmaltz committed Sep 6, 2023
1 parent 8f33042 commit 034ec06
Showing 1 changed file with 6 additions and 7 deletions.
13 changes: 6 additions & 7 deletions src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;

Expand All @@ -17,7 +18,6 @@ namespace Microsoft.IdentityModel.JsonWebTokens
/// </summary>
public class JsonWebToken : SecurityToken
{
internal object _audiencesLock = new();
private ClaimsIdentity _claimsIdentity;
private bool _wasClaimsIdentitySet;

Expand Down Expand Up @@ -614,12 +614,11 @@ public IEnumerable<string> Audiences
{
if (_audiences == null)
{
lock (_audiencesLock)
{
_audiences ??= Payload.TryGetValue(JwtRegisteredClaimNames.Aud, out IList<string> audiences) ?
(audiences is string[] audiencesArray ? audiencesArray : audiences.ToArray()) :
Array.Empty<string>();
}
var tmp = Payload.TryGetValue(JwtRegisteredClaimNames.Aud, out IList<string> audiences) ?
(audiences is string[] audiencesArray ? audiencesArray : audiences.ToArray()) :
Array.Empty<string>();

Interlocked.CompareExchange(ref _audiences, tmp, null);
}

return _audiences;
Expand Down

0 comments on commit 034ec06

Please sign in to comment.