AzureAD / azure-activedirectory-identitymodel-extensions-for-dotnet

IdentityModel extensions for .Net
MIT License
1.05k stars 396 forks source link

[Bug] JwtPayload serialisation seems to invoke ToString for complex object claim #2585

Open liviasossai opened 4 months ago

liviasossai commented 4 months ago

Documentation related to component

IdentityModel 7x releases notes.

Please check all that apply

Description of the issue

Hi, I noticed the JWT additional claim serialisation behaviour has changed after upgrading System.IdentityModel.Tokens.Jwt from version 6.x to 7.x. More specifically, when serialising a claim represented by a list of objects, JsonSecurityTokenHandler.WriteToken seems to invoke the object's ToString() method instead of serialising it. The following sample code:

        public static string GenerateJwt()
        {
            var listClaim = new MyClass[] { new() { Name = "test" } };
            var payload = new JwtPayload()
            {
                { "claim", 1.0 },
                { "listClaim", listClaim }
            };

            var securityKey = new RsaSecurityKey(RSA.Create());
            var signingCredentials = new SigningCredentials(securityKey, "RS256");

            var token = new JwtSecurityToken(new JwtHeader(signingCredentials), payload);

            return new JwtSecurityTokenHandler().WriteToken(token);
        }

Generates this JWT payload:

{
  "claim": 1,
  "listClaim": [
    "test_jwt.MyClass"
  ]
}

Previously, the payload was serialised as:

{
  "claim": 1,
  "listClaim": [
    {
      "Name": "test"
    }
  ]
}

The behaviour described above only happens if instantiating JwtPayload with the additional claims dictionary (Dictionary<string, object>). A possible workaround is to instantiate JsonPayload with a list of Claim objects as follows:

            var payload = new JwtPayload(
                new Claim[]
                {
                    new("claim", "1.0"),
                    new("listClaim", JsonSerializer.Serialize(listClaim), JsonClaimValueTypes.Json),
                });

I noticed this behaviour was introduced here. The 7.x releases notes mention some changes to the serialisation behaviour, but doesn't specify the one described above. Logging as a documentation issue as I am not sure if this behaviour change is expected (and not documented) or a bug.

Thanks.

pmaytak commented 1 week ago

Indeed this is an intended change. This has more info: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/2455#issuecomment-1911006805

We will update the docs.