uruk-project / Jwt

JSON Web Token implementation for .Net & .Net Core
MIT License
84 stars 13 forks source link

Add a claim with JWTArray #423

Closed MortalFlesh closed 4 years ago

MortalFlesh commented 4 years ago

Hello again, I really tried to figure out this myself, but I couldn't.

I need to add a custom claim to payload:

{
  ...,
  "groups": [
     "first",
     "second",
     "third"
  ]
}

but so far I can only add it to look like this:

{
  ...,
  "groups": {
    "groups": [
      "first",
      "second",
      "third"
    ]
  }
}

This code leads to a "double nested" groups:

let array =
    ["first"; "second"; "third"]
    |> List.map (fun v -> JwtValue(v))
    |> System.Linq.Enumerable.ToList // convert to Collection.Generic.List
    |> JwtArray

let property = JwtProperty("groups", array)
descriptor.AddClaim("groups", property)

I'd like to just add an array as claim

descriptor.AddClaim("groups", array)

but there is no such option.

I can create a JwtObject and add an array there, but it also needs a key and it has List<JwtProperty> _properties inside. JwtProperty AFAIK needs to have both name and value.


But if I create a token elsewhere, I can read value exactly the way I want to:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0MTg1YzQ0NC03OWNkLTRmNmUtODYwOC01N2E0NTI1YWFjNWYiLCJleHAiOjE2MTg3NDkyOTYsImlhdCI6MTU4NzY0NTI5NiwiaXNzIjoic2MtZWxpZ2liaWxpdHlDb25maWd1cmF0b3IiLCJncm91cHMiOlsiZmlyc3QiLCJzZWNvbmQiLCJ0aGlyZCJdfQ.gKXcjZkXLOI8MlImxiTRC4TuYa6UBvqw_Gb2ltJdZ4c
match result.Token.Payload.TryGetValue("groups") with
| true, groups -> printfn "groups <%A>:\n%A" (groups.Value.GetType()) groups.Value
| _ -> ()

Output:

groups <JsonWebToken.JwtArray>:
seq [JsonWebToken.JwtValue; JsonWebToken.JwtValue; JsonWebToken.JwtValue]

I even tried to fork it and "fix" it myself to the PR, but I don't know how to create a nameless property or claim.

ycrumeyrolle commented 4 years ago

TL; DR Try

descriptor.Payload.Add(new JwtProperty("groups", array))

Currently the IEnumerable is not directly supported as input. You must wrap it into a JwtArray, as you tried.

The JwtProperty class represents a JSON property, basicaly a property name and a property value. The JwtValue class represents a JSON value, without property name. The JwtArray class represents a JSON array, like the JwtValue. The JwtProperty support JSON primitives as value (number, string, boolean and null), the JwtObject for a nested object, and the JwtArray for a nested array.

As I understand to your requirement, you try to add an array of string as claim, which is legit. And it seems there is not AddClaim() overload with a JwtArray. The overload with a JwtProperty is mostly designed for adding a nested object, like in the Security Event Tokens "events": {"event1" : { "hello": "world" } }.

You can workaround the missing AddClaim() overload by adding the claim directly with the Payload property:

descriptor.Payload.Add(new JwtProperty("groups", array))

I expect to add a AddClaim() overload with a JwtArray, and with and array of string, which is the common use case.

MortalFlesh commented 4 years ago

Great, thanks for quick solution and I already created a PR https://github.com/ycrumeyrolle/Jwt/pull/424 to add this overload.