-
Notifications
You must be signed in to change notification settings - Fork 420
Description
Hi. Was wiring things up in a service and noticed that jwt.StandardClaims
assumes aud
is a string.
According to the RFC https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3 this field can sometimes be a string
. The way its written leads me to believe a []string
is actually more common, but that's interpretation.
The quick way I found around this was to use jwt.MapClaims
and serialize + deserialize this into a custom struct. Could this be improved by transforming aud
into a interface{}
and having a method on jwt.StandardClaims
like:
type St struct {
Aud interface{} `json:"aud"`
}
func (sc St) Audience() ([]string, error) {
if v, ok := sc.Aud.(string); ok {
return []string{v}, nil
} else if v, ok := sc.Aud.([]interface{}); ok {
var results []string
for _, s := range v {
if asString, isString := s.(string); isString {
results = append(results, asString)
} else {
return nil, e.New("found an aud that is not a string")
}
}
return results, nil
}
return nil, e.New("unparsable aud claim")
}
Simple tests to verify it works at some level at least:
func TestBla(t *testing.T) {
var singleAud St
err := json.Unmarshal([]byte(`{ "aud": "bla" }`), &singleAud)
require.NoError(t, err)
audience, err := singleAud.Audience()
require.NoError(t, err)
require.ElementsMatch(t, audience, []string{"bla"})
var multiAud St
err = json.Unmarshal([]byte(`{ "aud": [ "bla", "ble" ] }`), &multiAud)
require.NoError(t, err)
audience, err = multiAud.Audience()
require.NoError(t, err)
require.ElementsMatch(t, audience, []string{"bla", "ble"})
}
If aud
is the only parameter that can be either a string
or a []string
adding a new type might be a more pleasant experience:
type StandardClaimsWithSingleAud struct {
Aud string ...
}
type StandardClaimsWithMulitAud struct {
Aud []string ...
}
Is there already a way to deal with this in a typed fashion instead of dealing with the untyped jwt.MapClaims
?