Skip to content

Commit 1a11d37

Browse files
authored
fix: return ErrInvalidType for an invalid aud claim type in MapClaims (#511)
1 parent 0c0d487 commit 1a11d37

2 files changed

Lines changed: 47 additions & 0 deletions

File tree

map_claims.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,16 @@ func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) {
7777
}
7878
cs = append(cs, vs)
7979
}
80+
case nil:
81+
// The claim is either absent or explicitly null. As the claim is
82+
// optional, this is not an error and means "no value".
83+
return nil, nil
84+
default:
85+
// Any other type (e.g. a number, boolean or object) is invalid, which
86+
// is reported as an error to stay consistent with the other accessors
87+
// such as parseString and parseNumericDate, as well as with the
88+
// per-element type check performed on []any audiences above.
89+
return nil, newError(fmt.Sprintf("%s is invalid", key), ErrInvalidType)
8090
}
8191

8292
return cs, nil

map_claims_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package jwt
33
import (
44
"encoding/json"
55
"errors"
6+
"reflect"
67
"testing"
78
"time"
89
)
@@ -236,3 +237,39 @@ func TestMapClaims_GetExpirationTime_StringIsInvalidType(t *testing.T) {
236237
})
237238
}
238239
}
240+
241+
func TestMapClaims_GetAudience(t *testing.T) {
242+
tests := []struct {
243+
name string
244+
m MapClaims
245+
want ClaimStrings
246+
wantErr error // nil means no error; otherwise errors.Is(err, wantErr)
247+
}{
248+
// aud is optional: absent or null means "no audience", not an error.
249+
{name: "missing aud", m: MapClaims{}, want: nil, wantErr: nil},
250+
{name: "null aud", m: MapClaims{"aud": nil}, want: nil, wantErr: nil},
251+
// Valid shapes per RFC 7519: a single string or an array of strings.
252+
{name: "string aud", m: MapClaims{"aud": "example.com"}, want: ClaimStrings{"example.com"}, wantErr: nil},
253+
{name: "[]string aud", m: MapClaims{"aud": []string{"a", "b"}}, want: ClaimStrings{"a", "b"}, wantErr: nil},
254+
{name: "[]any of strings aud", m: MapClaims{"aud": []any{"a", "b"}}, want: ClaimStrings{"a", "b"}, wantErr: nil},
255+
// Invalid types must return ErrInvalidType, consistent with the other
256+
// MapClaims accessors (iss/sub/exp/nbf/iat) and with the per-element
257+
// check already performed on []any audiences.
258+
{name: "[]any with non-string element", m: MapClaims{"aud": []any{"a", 5}}, want: nil, wantErr: ErrInvalidType},
259+
{name: "wrong type: number", m: MapClaims{"aud": 123}, want: nil, wantErr: ErrInvalidType},
260+
{name: "wrong type: bool", m: MapClaims{"aud": true}, want: nil, wantErr: ErrInvalidType},
261+
{name: "wrong type: object", m: MapClaims{"aud": map[string]any{"x": 1}}, want: nil, wantErr: ErrInvalidType},
262+
}
263+
for _, tt := range tests {
264+
t.Run(tt.name, func(t *testing.T) {
265+
got, err := tt.m.GetAudience()
266+
if !errors.Is(err, tt.wantErr) {
267+
t.Errorf("MapClaims.GetAudience() error = %v, want %v", err, tt.wantErr)
268+
return
269+
}
270+
if tt.wantErr == nil && !reflect.DeepEqual(got, tt.want) {
271+
t.Errorf("MapClaims.GetAudience() = %#v, want %#v", got, tt.want)
272+
}
273+
})
274+
}
275+
}

0 commit comments

Comments
 (0)