azure-activedirectory-identitymodel-extensions-for-dotnet icon indicating copy to clipboard operation
azure-activedirectory-identitymodel-extensions-for-dotnet copied to clipboard

[Documentation] JwtPayload serialisation seems to invoke ToString for complex object claim

Open liviasossai opened this issue 3 months ago • 0 comments

Documentation related to component

IdentityModel 7x releases notes.

Please check all that apply

  • [ ] typo
  • [ ] documentation doesn't exist
  • [ ] documentation needs clarification
  • [ ] error(s) in the example
  • [x] needs an example

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.

liviasossai avatar May 06 '24 20:05 liviasossai