xref: /aosp_15_r20/external/tink/go/jwt/raw_jwt_test.go (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1*e7b1675dSTing-Kang Chang// Copyright 2021 Google LLC
2*e7b1675dSTing-Kang Chang//
3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang//
7*e7b1675dSTing-Kang Chang//      http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang//
9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang// limitations under the License.
14*e7b1675dSTing-Kang Chang//
15*e7b1675dSTing-Kang Chang////////////////////////////////////////////////////////////////////////////////
16*e7b1675dSTing-Kang Chang
17*e7b1675dSTing-Kang Changpackage jwt_test
18*e7b1675dSTing-Kang Chang
19*e7b1675dSTing-Kang Changimport (
20*e7b1675dSTing-Kang Chang	"testing"
21*e7b1675dSTing-Kang Chang	"time"
22*e7b1675dSTing-Kang Chang
23*e7b1675dSTing-Kang Chang	"github.com/google/go-cmp/cmp"
24*e7b1675dSTing-Kang Chang	"github.com/google/go-cmp/cmp/cmpopts"
25*e7b1675dSTing-Kang Chang	"github.com/google/tink/go/jwt"
26*e7b1675dSTing-Kang Chang)
27*e7b1675dSTing-Kang Chang
28*e7b1675dSTing-Kang Changconst (
29*e7b1675dSTing-Kang Chang	invalidUTF8     = "\xF4\x7F\xBF\xBF"
30*e7b1675dSTing-Kang Chang	validExpiration = 1640043004
31*e7b1675dSTing-Kang Chang)
32*e7b1675dSTing-Kang Chang
33*e7b1675dSTing-Kang Changtype testCase struct {
34*e7b1675dSTing-Kang Chang	tag   string
35*e7b1675dSTing-Kang Chang	opts  *jwt.RawJWTOptions
36*e7b1675dSTing-Kang Chang	json  string
37*e7b1675dSTing-Kang Chang	token *jwt.RawJWT
38*e7b1675dSTing-Kang Chang}
39*e7b1675dSTing-Kang Chang
40*e7b1675dSTing-Kang Changfunc refString(a string) *string {
41*e7b1675dSTing-Kang Chang	return &a
42*e7b1675dSTing-Kang Chang}
43*e7b1675dSTing-Kang Chang
44*e7b1675dSTing-Kang Changfunc refTime(ts int64) *time.Time {
45*e7b1675dSTing-Kang Chang	t := time.Unix(ts, 0)
46*e7b1675dSTing-Kang Chang	return &t
47*e7b1675dSTing-Kang Chang}
48*e7b1675dSTing-Kang Chang
49*e7b1675dSTing-Kang Changfunc TestCreatingRawJWTWithAllClaims(t *testing.T) {
50*e7b1675dSTing-Kang Chang	json := `{
51*e7b1675dSTing-Kang Chang				"sub": "tink-test-subject",
52*e7b1675dSTing-Kang Chang				"iss": "tink-test-issuer",
53*e7b1675dSTing-Kang Chang				"jti": "tink-jwt-id",
54*e7b1675dSTing-Kang Chang				"aud": ["aud-1", "aud-2"],
55*e7b1675dSTing-Kang Chang				"exp": 457888,
56*e7b1675dSTing-Kang Chang				"nbf": 450888,
57*e7b1675dSTing-Kang Chang				"iat": 400888,
58*e7b1675dSTing-Kang Chang				"cc-num": 1.67,
59*e7b1675dSTing-Kang Chang				"cc-bool": true,
60*e7b1675dSTing-Kang Chang				"cc-null": null,
61*e7b1675dSTing-Kang Chang				"cc-array": [1,2,3],
62*e7b1675dSTing-Kang Chang				"cc-string": "cc-val",
63*e7b1675dSTing-Kang Chang				"cc-object": {"nested-cc-num": 5.5}
64*e7b1675dSTing-Kang Chang			}`
65*e7b1675dSTing-Kang Chang
66*e7b1675dSTing-Kang Chang	opts := &jwt.RawJWTOptions{
67*e7b1675dSTing-Kang Chang		TypeHeader: refString("typeHeader"),
68*e7b1675dSTing-Kang Chang		Subject:    refString("tink-test-subject"),
69*e7b1675dSTing-Kang Chang		Issuer:     refString("tink-test-issuer"),
70*e7b1675dSTing-Kang Chang		JWTID:      refString("tink-jwt-id"),
71*e7b1675dSTing-Kang Chang		Audiences:  []string{"aud-1", "aud-2"},
72*e7b1675dSTing-Kang Chang		ExpiresAt:  refTime(457888),
73*e7b1675dSTing-Kang Chang		NotBefore:  refTime(450888),
74*e7b1675dSTing-Kang Chang		IssuedAt:   refTime(400888),
75*e7b1675dSTing-Kang Chang		CustomClaims: map[string]interface{}{
76*e7b1675dSTing-Kang Chang			"cc-num":    1.67,
77*e7b1675dSTing-Kang Chang			"cc-bool":   true,
78*e7b1675dSTing-Kang Chang			"cc-null":   nil,
79*e7b1675dSTing-Kang Chang			"cc-string": "cc-val",
80*e7b1675dSTing-Kang Chang			"cc-array":  []interface{}{1.0, 2.0, 3.0},
81*e7b1675dSTing-Kang Chang			"cc-object": map[string]interface{}{"nested-cc-num": 5.5},
82*e7b1675dSTing-Kang Chang		},
83*e7b1675dSTing-Kang Chang	}
84*e7b1675dSTing-Kang Chang	fromJSON, err := jwt.NewRawJWTFromJSON(refString("typeHeader"), []byte(json))
85*e7b1675dSTing-Kang Chang	if err != nil {
86*e7b1675dSTing-Kang Chang		t.Fatalf("jwt.NewRawJWTFromJSON(%q): %v", json, err)
87*e7b1675dSTing-Kang Chang	}
88*e7b1675dSTing-Kang Chang	fromOpts, err := jwt.NewRawJWT(opts)
89*e7b1675dSTing-Kang Chang	if err != nil {
90*e7b1675dSTing-Kang Chang		t.Fatalf("jwt.NewRawJWT(%v): %v", opts, err)
91*e7b1675dSTing-Kang Chang	}
92*e7b1675dSTing-Kang Chang	for _, tc := range []testCase{
93*e7b1675dSTing-Kang Chang		{
94*e7b1675dSTing-Kang Chang			tag:   "jwt.NewRawJWTFromJSON",
95*e7b1675dSTing-Kang Chang			token: fromJSON,
96*e7b1675dSTing-Kang Chang		},
97*e7b1675dSTing-Kang Chang		{
98*e7b1675dSTing-Kang Chang			tag:   "NewRawJWT",
99*e7b1675dSTing-Kang Chang			token: fromOpts,
100*e7b1675dSTing-Kang Chang		},
101*e7b1675dSTing-Kang Chang	} {
102*e7b1675dSTing-Kang Chang		if !tc.token.HasTypeHeader() {
103*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasTypeHeader() = false, want true")
104*e7b1675dSTing-Kang Chang		}
105*e7b1675dSTing-Kang Chang		if !tc.token.HasAudiences() {
106*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasAudiences() = false, want true")
107*e7b1675dSTing-Kang Chang		}
108*e7b1675dSTing-Kang Chang		if !tc.token.HasSubject() {
109*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasSubject() = false, want true")
110*e7b1675dSTing-Kang Chang		}
111*e7b1675dSTing-Kang Chang		if !tc.token.HasIssuer() {
112*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasIssuer() = false, want true")
113*e7b1675dSTing-Kang Chang		}
114*e7b1675dSTing-Kang Chang		if !tc.token.HasJWTID() {
115*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasJWTID() = false, want true")
116*e7b1675dSTing-Kang Chang		}
117*e7b1675dSTing-Kang Chang		if !tc.token.HasExpiration() {
118*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasExpiration() = false, want true")
119*e7b1675dSTing-Kang Chang		}
120*e7b1675dSTing-Kang Chang		if !tc.token.HasNotBefore() {
121*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasNotBefore() = false, want true")
122*e7b1675dSTing-Kang Chang		}
123*e7b1675dSTing-Kang Chang		if !tc.token.HasIssuedAt() {
124*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasIssuedAt() = false, want true")
125*e7b1675dSTing-Kang Chang		}
126*e7b1675dSTing-Kang Chang
127*e7b1675dSTing-Kang Chang		typeHeader, err := tc.token.TypeHeader()
128*e7b1675dSTing-Kang Chang		if err != nil {
129*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.TypeHeader() err = %v, want nil", err)
130*e7b1675dSTing-Kang Chang		}
131*e7b1675dSTing-Kang Chang		if !cmp.Equal(typeHeader, *opts.TypeHeader) {
132*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.TypeHeader() = %q, want %q", typeHeader, *opts.TypeHeader)
133*e7b1675dSTing-Kang Chang		}
134*e7b1675dSTing-Kang Chang		audiences, err := tc.token.Audiences()
135*e7b1675dSTing-Kang Chang		if err != nil {
136*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.Audiences() err = %v, want nil", err)
137*e7b1675dSTing-Kang Chang		}
138*e7b1675dSTing-Kang Chang		if !cmp.Equal(audiences, opts.Audiences) {
139*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.Audiences() = %q, want %q", audiences, opts.Audiences)
140*e7b1675dSTing-Kang Chang		}
141*e7b1675dSTing-Kang Chang		subject, err := tc.token.Subject()
142*e7b1675dSTing-Kang Chang		if err != nil {
143*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.Subject() err = %v, want nil", err)
144*e7b1675dSTing-Kang Chang		}
145*e7b1675dSTing-Kang Chang		if !cmp.Equal(subject, *opts.Subject) {
146*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.Subject() = %q, want %q", subject, *opts.Subject)
147*e7b1675dSTing-Kang Chang		}
148*e7b1675dSTing-Kang Chang		issuer, err := tc.token.Issuer()
149*e7b1675dSTing-Kang Chang		if err != nil {
150*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.Issuer() err = %v, want nil", err)
151*e7b1675dSTing-Kang Chang		}
152*e7b1675dSTing-Kang Chang		if !cmp.Equal(issuer, *opts.Issuer) {
153*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.Issuer() = %q, want %q", issuer, *opts.Issuer)
154*e7b1675dSTing-Kang Chang		}
155*e7b1675dSTing-Kang Chang		jwtID, err := tc.token.JWTID()
156*e7b1675dSTing-Kang Chang		if err != nil {
157*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.JWTID() err = %v, want nil", err)
158*e7b1675dSTing-Kang Chang		}
159*e7b1675dSTing-Kang Chang		if !cmp.Equal(jwtID, *opts.JWTID) {
160*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.JWTID() = %q, want %q", jwtID, *opts.JWTID)
161*e7b1675dSTing-Kang Chang		}
162*e7b1675dSTing-Kang Chang		expiresAt, err := tc.token.ExpiresAt()
163*e7b1675dSTing-Kang Chang		if err != nil {
164*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.ExpiresAt() err = %v, want nil", err)
165*e7b1675dSTing-Kang Chang		}
166*e7b1675dSTing-Kang Chang		if !cmp.Equal(expiresAt, *opts.ExpiresAt) {
167*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.ExpiresAt() = %q, want %q", expiresAt, *opts.ExpiresAt)
168*e7b1675dSTing-Kang Chang		}
169*e7b1675dSTing-Kang Chang		issuedAt, err := tc.token.IssuedAt()
170*e7b1675dSTing-Kang Chang		if err != nil {
171*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.IssuedAt() err = %v, want nil", err)
172*e7b1675dSTing-Kang Chang		}
173*e7b1675dSTing-Kang Chang		if !cmp.Equal(issuedAt, *opts.IssuedAt) {
174*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.IssuedAt() = %q, want %q", issuedAt, *opts.IssuedAt)
175*e7b1675dSTing-Kang Chang		}
176*e7b1675dSTing-Kang Chang		notBefore, err := tc.token.NotBefore()
177*e7b1675dSTing-Kang Chang		if err != nil {
178*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.NotBefore() err = %v, want nil", err)
179*e7b1675dSTing-Kang Chang		}
180*e7b1675dSTing-Kang Chang		if !cmp.Equal(notBefore, *opts.NotBefore) {
181*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.NotBefore() = %q, want %q", notBefore, *opts.NotBefore)
182*e7b1675dSTing-Kang Chang		}
183*e7b1675dSTing-Kang Chang		wantCustomClaims := []string{"cc-num", "cc-bool", "cc-null", "cc-string", "cc-array", "cc-object"}
184*e7b1675dSTing-Kang Chang		if !cmp.Equal(tc.token.CustomClaimNames(), wantCustomClaims, cmpopts.SortSlices(func(a, b string) bool { return a < b })) {
185*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.CustomClaimNames() = %q, want %q", tc.token.CustomClaimNames(), wantCustomClaims)
186*e7b1675dSTing-Kang Chang		}
187*e7b1675dSTing-Kang Chang		if !tc.token.HasNumberClaim("cc-num") {
188*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasNumberClaim('cc-num') = false, want true")
189*e7b1675dSTing-Kang Chang		}
190*e7b1675dSTing-Kang Chang		if !tc.token.HasBooleanClaim("cc-bool") {
191*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasBooleanClaim('cc-bool') = false, want true")
192*e7b1675dSTing-Kang Chang		}
193*e7b1675dSTing-Kang Chang		if !tc.token.HasNullClaim("cc-null") {
194*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasNullClaim('cc-null') = false, want true")
195*e7b1675dSTing-Kang Chang		}
196*e7b1675dSTing-Kang Chang		if !tc.token.HasStringClaim("cc-string") {
197*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasStringClaim('cc-string') = false, want true")
198*e7b1675dSTing-Kang Chang		}
199*e7b1675dSTing-Kang Chang		if !tc.token.HasArrayClaim("cc-array") {
200*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasArrayClaim('cc-array') = false, want true")
201*e7b1675dSTing-Kang Chang		}
202*e7b1675dSTing-Kang Chang		if !tc.token.HasObjectClaim("cc-object") {
203*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasObjectClaim('cc-object') = false, want true")
204*e7b1675dSTing-Kang Chang		}
205*e7b1675dSTing-Kang Chang
206*e7b1675dSTing-Kang Chang		number, err := tc.token.NumberClaim("cc-num")
207*e7b1675dSTing-Kang Chang		if err != nil {
208*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.NumberClaim('cc-num') err = %v, want nil", err)
209*e7b1675dSTing-Kang Chang		}
210*e7b1675dSTing-Kang Chang		if !cmp.Equal(number, opts.CustomClaims["cc-num"]) {
211*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.NumberClaim('cc-num') = %f, want %f", number, opts.CustomClaims["cc-num"])
212*e7b1675dSTing-Kang Chang		}
213*e7b1675dSTing-Kang Chang		boolean, err := tc.token.BooleanClaim("cc-bool")
214*e7b1675dSTing-Kang Chang		if err != nil {
215*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.BooleanClaim('cc-bool') err = %v, want nil", err)
216*e7b1675dSTing-Kang Chang		}
217*e7b1675dSTing-Kang Chang		if !cmp.Equal(boolean, opts.CustomClaims["cc-bool"]) {
218*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.BooleanClaim('cc-bool') = %v, want %v", boolean, opts.CustomClaims["cc-bool"])
219*e7b1675dSTing-Kang Chang		}
220*e7b1675dSTing-Kang Chang		str, err := tc.token.StringClaim("cc-string")
221*e7b1675dSTing-Kang Chang		if err != nil {
222*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.StringClaim('cc-string') err = %v, want nil", err)
223*e7b1675dSTing-Kang Chang		}
224*e7b1675dSTing-Kang Chang		if !cmp.Equal(str, opts.CustomClaims["cc-string"]) {
225*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.StringClaim('cc-string') = %q, want %q", str, opts.CustomClaims["cc-string"])
226*e7b1675dSTing-Kang Chang		}
227*e7b1675dSTing-Kang Chang		array, err := tc.token.ArrayClaim("cc-array")
228*e7b1675dSTing-Kang Chang		if err != nil {
229*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.ArrayClaim('cc-array') err = %v, want nil", err)
230*e7b1675dSTing-Kang Chang		}
231*e7b1675dSTing-Kang Chang		if !cmp.Equal(array, opts.CustomClaims["cc-array"]) {
232*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.ArrayClaim('cc-array') = %q, want %q", array, opts.CustomClaims["cc-array"])
233*e7b1675dSTing-Kang Chang		}
234*e7b1675dSTing-Kang Chang		object, err := tc.token.ObjectClaim("cc-object")
235*e7b1675dSTing-Kang Chang		if err != nil {
236*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.ObjectClaim('cc-object') err = %v, want nil", err)
237*e7b1675dSTing-Kang Chang		}
238*e7b1675dSTing-Kang Chang		if !cmp.Equal(object, opts.CustomClaims["cc-object"]) {
239*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.ObjectClaim('cc-object') = %q, want %q", object, opts.CustomClaims["cc-object"])
240*e7b1675dSTing-Kang Chang		}
241*e7b1675dSTing-Kang Chang	}
242*e7b1675dSTing-Kang Chang}
243*e7b1675dSTing-Kang Chang
244*e7b1675dSTing-Kang Changfunc TestGeneratingRawJWTWithoutClaims(t *testing.T) {
245*e7b1675dSTing-Kang Chang	jsonToken, err := jwt.NewRawJWTFromJSON(nil, []byte("{}"))
246*e7b1675dSTing-Kang Chang	if err != nil {
247*e7b1675dSTing-Kang Chang		t.Fatalf("jwt.NewRawJWTFromJSON({}): %v", err)
248*e7b1675dSTing-Kang Chang	}
249*e7b1675dSTing-Kang Chang	optsToken, err := jwt.NewRawJWT(&jwt.RawJWTOptions{WithoutExpiration: true})
250*e7b1675dSTing-Kang Chang	if err != nil {
251*e7b1675dSTing-Kang Chang		t.Fatalf("NewRawJWT with no claims: %v", err)
252*e7b1675dSTing-Kang Chang	}
253*e7b1675dSTing-Kang Chang	for _, tc := range []testCase{
254*e7b1675dSTing-Kang Chang		{
255*e7b1675dSTing-Kang Chang			tag:   "jwt.NewRawJWTFromJSON",
256*e7b1675dSTing-Kang Chang			token: jsonToken,
257*e7b1675dSTing-Kang Chang		},
258*e7b1675dSTing-Kang Chang		{
259*e7b1675dSTing-Kang Chang			tag:   "NewRawJWT",
260*e7b1675dSTing-Kang Chang			token: optsToken,
261*e7b1675dSTing-Kang Chang		},
262*e7b1675dSTing-Kang Chang	} {
263*e7b1675dSTing-Kang Chang		if tc.token.HasTypeHeader() {
264*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasTypeHeader() = true, want false")
265*e7b1675dSTing-Kang Chang		}
266*e7b1675dSTing-Kang Chang		if tc.token.HasAudiences() {
267*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasAudiences() = true, want false")
268*e7b1675dSTing-Kang Chang		}
269*e7b1675dSTing-Kang Chang		if tc.token.HasSubject() {
270*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasSubject() = true, want false")
271*e7b1675dSTing-Kang Chang		}
272*e7b1675dSTing-Kang Chang		if tc.token.HasIssuer() {
273*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasIssuer() = true, want false")
274*e7b1675dSTing-Kang Chang		}
275*e7b1675dSTing-Kang Chang		if tc.token.HasJWTID() {
276*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasJWTID() = true, want false")
277*e7b1675dSTing-Kang Chang		}
278*e7b1675dSTing-Kang Chang		if tc.token.HasExpiration() {
279*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasExpiration() = true, want false")
280*e7b1675dSTing-Kang Chang		}
281*e7b1675dSTing-Kang Chang		if tc.token.HasNotBefore() {
282*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasNotBefore() = true, want false")
283*e7b1675dSTing-Kang Chang		}
284*e7b1675dSTing-Kang Chang		if tc.token.HasIssuedAt() {
285*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.HasIssuedAt() = true, want false")
286*e7b1675dSTing-Kang Chang		}
287*e7b1675dSTing-Kang Chang		if _, err := tc.token.Audiences(); err == nil {
288*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.Audiences() err = nil, want error")
289*e7b1675dSTing-Kang Chang		}
290*e7b1675dSTing-Kang Chang		if _, err := tc.token.Subject(); err == nil {
291*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.Subject() err = nil, want error")
292*e7b1675dSTing-Kang Chang		}
293*e7b1675dSTing-Kang Chang		if _, err := tc.token.Issuer(); err == nil {
294*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.Issuer() err = nil, want error")
295*e7b1675dSTing-Kang Chang		}
296*e7b1675dSTing-Kang Chang		if _, err := tc.token.JWTID(); err == nil {
297*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.JWTID() err = nil, want error")
298*e7b1675dSTing-Kang Chang		}
299*e7b1675dSTing-Kang Chang		if _, err := tc.token.ExpiresAt(); err == nil {
300*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.ExpiresAt() err = nil, want error")
301*e7b1675dSTing-Kang Chang		}
302*e7b1675dSTing-Kang Chang		if _, err := tc.token.IssuedAt(); err == nil {
303*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.IssuedAt() err = nil, want error")
304*e7b1675dSTing-Kang Chang		}
305*e7b1675dSTing-Kang Chang		if _, err := tc.token.NotBefore(); err == nil {
306*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.NotBefore() err = nil, want error")
307*e7b1675dSTing-Kang Chang		}
308*e7b1675dSTing-Kang Chang		if !cmp.Equal(tc.token.CustomClaimNames(), []string{}) {
309*e7b1675dSTing-Kang Chang			t.Errorf("tc.token.CustomClaimNames() = %q want %q", tc.token.CustomClaimNames(), []string{})
310*e7b1675dSTing-Kang Chang		}
311*e7b1675dSTing-Kang Chang	}
312*e7b1675dSTing-Kang Chang}
313*e7b1675dSTing-Kang Chang
314*e7b1675dSTing-Kang Changfunc TestNewRawJWTLargeValidTimestamps(t *testing.T) {
315*e7b1675dSTing-Kang Chang	opts := &jwt.RawJWTOptions{
316*e7b1675dSTing-Kang Chang		TypeHeader: refString("typeHeader"),
317*e7b1675dSTing-Kang Chang		ExpiresAt:  refTime(253402300799),
318*e7b1675dSTing-Kang Chang		NotBefore:  refTime(253402300700),
319*e7b1675dSTing-Kang Chang		IssuedAt:   refTime(253402300000),
320*e7b1675dSTing-Kang Chang	}
321*e7b1675dSTing-Kang Chang	token, err := jwt.NewRawJWT(opts)
322*e7b1675dSTing-Kang Chang	if err != nil {
323*e7b1675dSTing-Kang Chang		t.Fatalf("generating RawJWT with valid timestamps (%q, %q, %q): %v", opts.ExpiresAt, opts.NotBefore, opts.IssuedAt, err)
324*e7b1675dSTing-Kang Chang	}
325*e7b1675dSTing-Kang Chang	expiresAt, err := token.ExpiresAt()
326*e7b1675dSTing-Kang Chang	if err != nil {
327*e7b1675dSTing-Kang Chang		t.Errorf("tc.token.ExpiresAt() err = %v, want nil", err)
328*e7b1675dSTing-Kang Chang	}
329*e7b1675dSTing-Kang Chang	if !cmp.Equal(expiresAt, *opts.ExpiresAt) {
330*e7b1675dSTing-Kang Chang		t.Errorf("tc.token.ExpiresAt() = %q want %q", expiresAt, *opts.ExpiresAt)
331*e7b1675dSTing-Kang Chang	}
332*e7b1675dSTing-Kang Chang
333*e7b1675dSTing-Kang Chang	notBefore, err := token.NotBefore()
334*e7b1675dSTing-Kang Chang	if err != nil {
335*e7b1675dSTing-Kang Chang		t.Errorf("tc.token.NotBefore() err = %v, want nil", err)
336*e7b1675dSTing-Kang Chang	}
337*e7b1675dSTing-Kang Chang	if !cmp.Equal(notBefore, *opts.NotBefore) {
338*e7b1675dSTing-Kang Chang		t.Errorf("tc.token.NotBefore() = %q want %q", notBefore, *opts.NotBefore)
339*e7b1675dSTing-Kang Chang	}
340*e7b1675dSTing-Kang Chang
341*e7b1675dSTing-Kang Chang	issuedAt, err := token.IssuedAt()
342*e7b1675dSTing-Kang Chang	if err != nil {
343*e7b1675dSTing-Kang Chang		t.Errorf("tc.token.IssuedAt() err = %v, want nil", err)
344*e7b1675dSTing-Kang Chang	}
345*e7b1675dSTing-Kang Chang	if !cmp.Equal(issuedAt, *opts.IssuedAt) {
346*e7b1675dSTing-Kang Chang		t.Errorf("tc.token.IssuedAt() = %q want %q", issuedAt, *opts.IssuedAt)
347*e7b1675dSTing-Kang Chang	}
348*e7b1675dSTing-Kang Chang}
349*e7b1675dSTing-Kang Chang
350*e7b1675dSTing-Kang Changfunc TestNewRawJWTSingleStringAudience(t *testing.T) {
351*e7b1675dSTing-Kang Chang	opts := &jwt.RawJWTOptions{
352*e7b1675dSTing-Kang Chang		WithoutExpiration: true,
353*e7b1675dSTing-Kang Chang		Audience:          refString("tink-aud"),
354*e7b1675dSTing-Kang Chang	}
355*e7b1675dSTing-Kang Chang	rawJWT, err := jwt.NewRawJWT(opts)
356*e7b1675dSTing-Kang Chang	if err != nil {
357*e7b1675dSTing-Kang Chang		t.Fatalf("generating RawJWT with a single audience: %v", err)
358*e7b1675dSTing-Kang Chang	}
359*e7b1675dSTing-Kang Chang	aud, err := rawJWT.Audiences()
360*e7b1675dSTing-Kang Chang	if err != nil {
361*e7b1675dSTing-Kang Chang		t.Errorf("getting audience from token: %v", err)
362*e7b1675dSTing-Kang Chang	}
363*e7b1675dSTing-Kang Chang	want := []string{*opts.Audience}
364*e7b1675dSTing-Kang Chang	if !cmp.Equal(aud, want) {
365*e7b1675dSTing-Kang Chang		t.Errorf("rawJWT.Audiences() = %q, want %q", aud, want)
366*e7b1675dSTing-Kang Chang	}
367*e7b1675dSTing-Kang Chang}
368*e7b1675dSTing-Kang Chang
369*e7b1675dSTing-Kang Changfunc TestSingleStringAudienceFromJSON(t *testing.T) {
370*e7b1675dSTing-Kang Chang	rawJWT, err := jwt.NewRawJWTFromJSON(nil, []byte(`{"aud": "tink-aud"}`))
371*e7b1675dSTing-Kang Chang	if err != nil {
372*e7b1675dSTing-Kang Chang		t.Fatalf("parsing valid RawJWT: %v", err)
373*e7b1675dSTing-Kang Chang	}
374*e7b1675dSTing-Kang Chang	aud, err := rawJWT.Audiences()
375*e7b1675dSTing-Kang Chang	if err != nil {
376*e7b1675dSTing-Kang Chang		t.Errorf("getting audience from token: %v", err)
377*e7b1675dSTing-Kang Chang	}
378*e7b1675dSTing-Kang Chang	want := []string{"tink-aud"}
379*e7b1675dSTing-Kang Chang	if !cmp.Equal(aud, want) {
380*e7b1675dSTing-Kang Chang		t.Errorf("rawJWT.Audiences() = %q, want %q", aud, want)
381*e7b1675dSTing-Kang Chang	}
382*e7b1675dSTing-Kang Chang}
383*e7b1675dSTing-Kang Chang
384*e7b1675dSTing-Kang Changfunc TestNewRawJWTValidationFailures(t *testing.T) {
385*e7b1675dSTing-Kang Chang	testCases := []testCase{
386*e7b1675dSTing-Kang Chang		{
387*e7b1675dSTing-Kang Chang			tag: "empty jwt.RawJWTOptions options fails",
388*e7b1675dSTing-Kang Chang		},
389*e7b1675dSTing-Kang Chang		{
390*e7b1675dSTing-Kang Chang			tag: "no ExpiresAt specified and WithoutExpiration = false fails",
391*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
392*e7b1675dSTing-Kang Chang				Audiences: []string{"tink-foo"},
393*e7b1675dSTing-Kang Chang			},
394*e7b1675dSTing-Kang Chang		},
395*e7b1675dSTing-Kang Chang		{
396*e7b1675dSTing-Kang Chang			tag: "ExpiresAt and WithoutExpiration = true fails",
397*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
398*e7b1675dSTing-Kang Chang				Audiences:         []string{"tink-foo"},
399*e7b1675dSTing-Kang Chang				ExpiresAt:         refTime(validExpiration),
400*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
401*e7b1675dSTing-Kang Chang			},
402*e7b1675dSTing-Kang Chang		},
403*e7b1675dSTing-Kang Chang		{
404*e7b1675dSTing-Kang Chang			tag: "specifying Audenience and Audiences fails",
405*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
406*e7b1675dSTing-Kang Chang				Audiences:         []string{"tink-foo"},
407*e7b1675dSTing-Kang Chang				Audience:          refString("tink-bar"),
408*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
409*e7b1675dSTing-Kang Chang			},
410*e7b1675dSTing-Kang Chang		},
411*e7b1675dSTing-Kang Chang		{
412*e7b1675dSTing-Kang Chang			tag: "empty audiences array fails",
413*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
414*e7b1675dSTing-Kang Chang				ExpiresAt: refTime(validExpiration),
415*e7b1675dSTing-Kang Chang				Audiences: []string{},
416*e7b1675dSTing-Kang Chang			},
417*e7b1675dSTing-Kang Chang		},
418*e7b1675dSTing-Kang Chang		{
419*e7b1675dSTing-Kang Chang			tag: "audiences with invalid UTF-8 string fails",
420*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
421*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
422*e7b1675dSTing-Kang Chang				Audiences:         []string{"valid", invalidUTF8},
423*e7b1675dSTing-Kang Chang			},
424*e7b1675dSTing-Kang Chang		},
425*e7b1675dSTing-Kang Chang		{
426*e7b1675dSTing-Kang Chang			tag: "custom claims containing registered subject claims fails",
427*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
428*e7b1675dSTing-Kang Chang				Audiences: []string{"tink-foo"},
429*e7b1675dSTing-Kang Chang				ExpiresAt: refTime(validExpiration),
430*e7b1675dSTing-Kang Chang				CustomClaims: map[string]interface{}{
431*e7b1675dSTing-Kang Chang					"sub": "overwrite",
432*e7b1675dSTing-Kang Chang				},
433*e7b1675dSTing-Kang Chang			},
434*e7b1675dSTing-Kang Chang		},
435*e7b1675dSTing-Kang Chang		{
436*e7b1675dSTing-Kang Chang			tag: "custom claims containing registered issuer claims fails",
437*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
438*e7b1675dSTing-Kang Chang				Audiences: []string{"tink-foo"},
439*e7b1675dSTing-Kang Chang				ExpiresAt: refTime(validExpiration),
440*e7b1675dSTing-Kang Chang				CustomClaims: map[string]interface{}{
441*e7b1675dSTing-Kang Chang					"iss": "overwrite",
442*e7b1675dSTing-Kang Chang				},
443*e7b1675dSTing-Kang Chang			},
444*e7b1675dSTing-Kang Chang		},
445*e7b1675dSTing-Kang Chang		{
446*e7b1675dSTing-Kang Chang			tag: "custom claims containing registered jwt id claims fails",
447*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
448*e7b1675dSTing-Kang Chang				Audiences: []string{"tink-foo"},
449*e7b1675dSTing-Kang Chang				ExpiresAt: refTime(validExpiration),
450*e7b1675dSTing-Kang Chang				CustomClaims: map[string]interface{}{
451*e7b1675dSTing-Kang Chang					"jti": "overwrite",
452*e7b1675dSTing-Kang Chang				},
453*e7b1675dSTing-Kang Chang			},
454*e7b1675dSTing-Kang Chang		},
455*e7b1675dSTing-Kang Chang		{
456*e7b1675dSTing-Kang Chang			tag: "custom claims containing registered expiration claims fails",
457*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
458*e7b1675dSTing-Kang Chang				Audiences: []string{"tink-foo"},
459*e7b1675dSTing-Kang Chang				ExpiresAt: refTime(validExpiration),
460*e7b1675dSTing-Kang Chang				CustomClaims: map[string]interface{}{
461*e7b1675dSTing-Kang Chang					"exp": "overwrite",
462*e7b1675dSTing-Kang Chang				},
463*e7b1675dSTing-Kang Chang			},
464*e7b1675dSTing-Kang Chang		},
465*e7b1675dSTing-Kang Chang		{
466*e7b1675dSTing-Kang Chang			tag: "custom claims containing registered audience claims fails",
467*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
468*e7b1675dSTing-Kang Chang				Audiences:         []string{"tink-foo"},
469*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
470*e7b1675dSTing-Kang Chang				CustomClaims: map[string]interface{}{
471*e7b1675dSTing-Kang Chang					"aud": []interface{}{"overwrite"},
472*e7b1675dSTing-Kang Chang				},
473*e7b1675dSTing-Kang Chang			},
474*e7b1675dSTing-Kang Chang		},
475*e7b1675dSTing-Kang Chang		{
476*e7b1675dSTing-Kang Chang			tag: "custom claims with non standard JSON types fails",
477*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
478*e7b1675dSTing-Kang Chang				Audiences: []string{"tink-foo"},
479*e7b1675dSTing-Kang Chang				ExpiresAt: refTime(validExpiration),
480*e7b1675dSTing-Kang Chang				CustomClaims: map[string]interface{}{
481*e7b1675dSTing-Kang Chang					"complex": time.Time{},
482*e7b1675dSTing-Kang Chang				},
483*e7b1675dSTing-Kang Chang			},
484*e7b1675dSTing-Kang Chang		},
485*e7b1675dSTing-Kang Chang		{
486*e7b1675dSTing-Kang Chang			tag: "non UTF-8 string on isser claim fails",
487*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
488*e7b1675dSTing-Kang Chang				Audiences: []string{"tink-foo"},
489*e7b1675dSTing-Kang Chang				ExpiresAt: refTime(validExpiration),
490*e7b1675dSTing-Kang Chang				Issuer:    refString(invalidUTF8),
491*e7b1675dSTing-Kang Chang			},
492*e7b1675dSTing-Kang Chang		},
493*e7b1675dSTing-Kang Chang		{
494*e7b1675dSTing-Kang Chang			tag: "non UTF-8 string on subject claim fails",
495*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
496*e7b1675dSTing-Kang Chang				Audiences:         []string{"tink-foo"},
497*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
498*e7b1675dSTing-Kang Chang				Subject:           refString(invalidUTF8),
499*e7b1675dSTing-Kang Chang			},
500*e7b1675dSTing-Kang Chang		},
501*e7b1675dSTing-Kang Chang		{
502*e7b1675dSTing-Kang Chang			tag: "non UTF-8 string on JWT ID claim fails",
503*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
504*e7b1675dSTing-Kang Chang				Audiences:         []string{"tink-foo"},
505*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
506*e7b1675dSTing-Kang Chang				JWTID:             refString(invalidUTF8),
507*e7b1675dSTing-Kang Chang			},
508*e7b1675dSTing-Kang Chang		},
509*e7b1675dSTing-Kang Chang		{
510*e7b1675dSTing-Kang Chang			tag: "non UTF-8 string on custom claim fails",
511*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
512*e7b1675dSTing-Kang Chang				Audiences: []string{"tink-foo"},
513*e7b1675dSTing-Kang Chang				Issuer:    refString("ise-testing"),
514*e7b1675dSTing-Kang Chang				ExpiresAt: refTime(validExpiration),
515*e7b1675dSTing-Kang Chang				CustomClaims: map[string]interface{}{
516*e7b1675dSTing-Kang Chang					"esoteric": invalidUTF8,
517*e7b1675dSTing-Kang Chang				},
518*e7b1675dSTing-Kang Chang			},
519*e7b1675dSTing-Kang Chang		},
520*e7b1675dSTing-Kang Chang		{
521*e7b1675dSTing-Kang Chang			tag: "issued at timestamp greater than valid JWT max time fails",
522*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
523*e7b1675dSTing-Kang Chang				Audiences: []string{"tink-foo"},
524*e7b1675dSTing-Kang Chang				ExpiresAt: refTime(validExpiration),
525*e7b1675dSTing-Kang Chang				IssuedAt:  refTime(253402300800),
526*e7b1675dSTing-Kang Chang			},
527*e7b1675dSTing-Kang Chang		},
528*e7b1675dSTing-Kang Chang		{
529*e7b1675dSTing-Kang Chang			tag: "expires at timestamp greater than valid JWT max time fails",
530*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
531*e7b1675dSTing-Kang Chang				Audiences: []string{"tink-foo"},
532*e7b1675dSTing-Kang Chang				ExpiresAt: refTime(253402300800),
533*e7b1675dSTing-Kang Chang			},
534*e7b1675dSTing-Kang Chang		},
535*e7b1675dSTing-Kang Chang		{
536*e7b1675dSTing-Kang Chang			tag: "not before timestamp smaller than valid JWT min time fails",
537*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
538*e7b1675dSTing-Kang Chang				Audiences: []string{"tink-foo"},
539*e7b1675dSTing-Kang Chang				ExpiresAt: refTime(validExpiration),
540*e7b1675dSTing-Kang Chang				NotBefore: refTime(-5),
541*e7b1675dSTing-Kang Chang			},
542*e7b1675dSTing-Kang Chang		},
543*e7b1675dSTing-Kang Chang	}
544*e7b1675dSTing-Kang Chang	for _, tc := range testCases {
545*e7b1675dSTing-Kang Chang		t.Run(tc.tag, func(t *testing.T) {
546*e7b1675dSTing-Kang Chang			_, err := jwt.NewRawJWT(tc.opts)
547*e7b1675dSTing-Kang Chang			if err == nil {
548*e7b1675dSTing-Kang Chang				t.Errorf("expected error instead got nil")
549*e7b1675dSTing-Kang Chang			}
550*e7b1675dSTing-Kang Chang		})
551*e7b1675dSTing-Kang Chang	}
552*e7b1675dSTing-Kang Chang}
553*e7b1675dSTing-Kang Chang
554*e7b1675dSTing-Kang Changfunc TestJSONPayload(t *testing.T) {
555*e7b1675dSTing-Kang Chang	for _, tc := range []testCase{
556*e7b1675dSTing-Kang Chang		{
557*e7b1675dSTing-Kang Chang			tag: "subject",
558*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
559*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
560*e7b1675dSTing-Kang Chang				Subject:           refString("tink-subject"),
561*e7b1675dSTing-Kang Chang			},
562*e7b1675dSTing-Kang Chang			json: `{"sub":"tink-subject"}`,
563*e7b1675dSTing-Kang Chang		},
564*e7b1675dSTing-Kang Chang		{
565*e7b1675dSTing-Kang Chang			tag: "audience list",
566*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
567*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
568*e7b1675dSTing-Kang Chang				Audiences:         []string{"one"},
569*e7b1675dSTing-Kang Chang			},
570*e7b1675dSTing-Kang Chang			json: `{"aud":["one"]}`,
571*e7b1675dSTing-Kang Chang		},
572*e7b1675dSTing-Kang Chang		{
573*e7b1675dSTing-Kang Chang			tag: "audience string",
574*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
575*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
576*e7b1675dSTing-Kang Chang				Audience:          refString("one"),
577*e7b1675dSTing-Kang Chang			},
578*e7b1675dSTing-Kang Chang			json: `{"aud":"one"}`,
579*e7b1675dSTing-Kang Chang		},
580*e7b1675dSTing-Kang Chang		{
581*e7b1675dSTing-Kang Chang			tag: "issuer",
582*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
583*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
584*e7b1675dSTing-Kang Chang				Issuer:            refString("tink-test"),
585*e7b1675dSTing-Kang Chang			},
586*e7b1675dSTing-Kang Chang			json: `{"iss":"tink-test"}`,
587*e7b1675dSTing-Kang Chang		},
588*e7b1675dSTing-Kang Chang		{
589*e7b1675dSTing-Kang Chang			tag: "jwt id",
590*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
591*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
592*e7b1675dSTing-Kang Chang				JWTID:             refString("tink-id"),
593*e7b1675dSTing-Kang Chang			},
594*e7b1675dSTing-Kang Chang			json: `{"jti":"tink-id"}`,
595*e7b1675dSTing-Kang Chang		},
596*e7b1675dSTing-Kang Chang		{
597*e7b1675dSTing-Kang Chang			tag: "issued at",
598*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
599*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
600*e7b1675dSTing-Kang Chang				IssuedAt:          refTime(78324),
601*e7b1675dSTing-Kang Chang			},
602*e7b1675dSTing-Kang Chang			json: `{"iat":78324}`,
603*e7b1675dSTing-Kang Chang		},
604*e7b1675dSTing-Kang Chang		{
605*e7b1675dSTing-Kang Chang			tag: "not before",
606*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
607*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
608*e7b1675dSTing-Kang Chang				NotBefore:         refTime(78324),
609*e7b1675dSTing-Kang Chang			},
610*e7b1675dSTing-Kang Chang			json: `{"nbf":78324}`,
611*e7b1675dSTing-Kang Chang		},
612*e7b1675dSTing-Kang Chang		{
613*e7b1675dSTing-Kang Chang			tag: "expiration",
614*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
615*e7b1675dSTing-Kang Chang				ExpiresAt: refTime(78324),
616*e7b1675dSTing-Kang Chang			},
617*e7b1675dSTing-Kang Chang			json: `{"exp":78324}`,
618*e7b1675dSTing-Kang Chang		},
619*e7b1675dSTing-Kang Chang		{
620*e7b1675dSTing-Kang Chang			tag: "integer",
621*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
622*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
623*e7b1675dSTing-Kang Chang				CustomClaims: map[string]interface{}{
624*e7b1675dSTing-Kang Chang					"num": 1,
625*e7b1675dSTing-Kang Chang				},
626*e7b1675dSTing-Kang Chang			},
627*e7b1675dSTing-Kang Chang			json: `{"num":1}`,
628*e7b1675dSTing-Kang Chang		},
629*e7b1675dSTing-Kang Chang		{
630*e7b1675dSTing-Kang Chang			tag: "custom-claim",
631*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
632*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
633*e7b1675dSTing-Kang Chang				CustomClaims: map[string]interface{}{
634*e7b1675dSTing-Kang Chang					"cust": []interface{}{map[string]interface{}{"key": "val"}},
635*e7b1675dSTing-Kang Chang				},
636*e7b1675dSTing-Kang Chang			},
637*e7b1675dSTing-Kang Chang			json: `{"cust":[{"key":"val"}]}`,
638*e7b1675dSTing-Kang Chang		},
639*e7b1675dSTing-Kang Chang		{
640*e7b1675dSTing-Kang Chang			tag: "no claims",
641*e7b1675dSTing-Kang Chang			opts: &jwt.RawJWTOptions{
642*e7b1675dSTing-Kang Chang				WithoutExpiration: true,
643*e7b1675dSTing-Kang Chang			},
644*e7b1675dSTing-Kang Chang			json: `{}`,
645*e7b1675dSTing-Kang Chang		},
646*e7b1675dSTing-Kang Chang	} {
647*e7b1675dSTing-Kang Chang		t.Run(tc.tag, func(t *testing.T) {
648*e7b1675dSTing-Kang Chang			token, err := jwt.NewRawJWT(tc.opts)
649*e7b1675dSTing-Kang Chang			if err != nil {
650*e7b1675dSTing-Kang Chang				t.Errorf("generating valid RawJWT: %v", err)
651*e7b1675dSTing-Kang Chang			}
652*e7b1675dSTing-Kang Chang			j, err := token.JSONPayload()
653*e7b1675dSTing-Kang Chang			if err != nil {
654*e7b1675dSTing-Kang Chang				t.Errorf("calling JSONPayload() on rawJWT: %v", err)
655*e7b1675dSTing-Kang Chang			}
656*e7b1675dSTing-Kang Chang			if !cmp.Equal(string(j), tc.json) {
657*e7b1675dSTing-Kang Chang				t.Fatalf("JSONPayload output got %v, expected %v", string(j), tc.json)
658*e7b1675dSTing-Kang Chang			}
659*e7b1675dSTing-Kang Chang		})
660*e7b1675dSTing-Kang Chang	}
661*e7b1675dSTing-Kang Chang}
662*e7b1675dSTing-Kang Chang
663*e7b1675dSTing-Kang Changfunc TestFromJSONValidationFailures(t *testing.T) {
664*e7b1675dSTing-Kang Chang	testCases := []testCase{
665*e7b1675dSTing-Kang Chang		{
666*e7b1675dSTing-Kang Chang			tag:  "json with empty audience",
667*e7b1675dSTing-Kang Chang			json: `{"sub": "tink", "aud": []}`,
668*e7b1675dSTing-Kang Chang		},
669*e7b1675dSTing-Kang Chang		{
670*e7b1675dSTing-Kang Chang			tag:  "json with audience of wrong type",
671*e7b1675dSTing-Kang Chang			json: `{"aud": 5}`,
672*e7b1675dSTing-Kang Chang		},
673*e7b1675dSTing-Kang Chang		{
674*e7b1675dSTing-Kang Chang			tag:  "json with audiences of wrong type",
675*e7b1675dSTing-Kang Chang			json: `{"aud": ["one", null]}`,
676*e7b1675dSTing-Kang Chang		},
677*e7b1675dSTing-Kang Chang		{
678*e7b1675dSTing-Kang Chang			tag:  "json with registered claim with wrong type",
679*e7b1675dSTing-Kang Chang			json: `{"sub": 1}`,
680*e7b1675dSTing-Kang Chang		},
681*e7b1675dSTing-Kang Chang		{
682*e7b1675dSTing-Kang Chang			tag:  "json with non UTF-8 string on subject claim fails",
683*e7b1675dSTing-Kang Chang			json: `{"sub": "\xF4\x7F\xBF\xBF"}`,
684*e7b1675dSTing-Kang Chang		},
685*e7b1675dSTing-Kang Chang		{
686*e7b1675dSTing-Kang Chang			tag:  "json with non UTF-8 string on issuer claim fails",
687*e7b1675dSTing-Kang Chang			json: `{"iss": "\xF4\x7F\xBF\xBF"}`,
688*e7b1675dSTing-Kang Chang		},
689*e7b1675dSTing-Kang Chang		{
690*e7b1675dSTing-Kang Chang			tag:  "json with non UTF-8 string on jwt id claim fails",
691*e7b1675dSTing-Kang Chang			json: `{"jti": "\xF4\x7F\xBF\xBF"}`,
692*e7b1675dSTing-Kang Chang		},
693*e7b1675dSTing-Kang Chang		{
694*e7b1675dSTing-Kang Chang			tag:  "json with `not before` timestamp claim greater than valid JWT max time fails",
695*e7b1675dSTing-Kang Chang			json: `{"nbf": 253402301799}`,
696*e7b1675dSTing-Kang Chang		},
697*e7b1675dSTing-Kang Chang		{
698*e7b1675dSTing-Kang Chang			tag:  "json with `issued at` timestamp claim greater than valid JWT max time fails",
699*e7b1675dSTing-Kang Chang			json: `{"iat": 253402301799}`,
700*e7b1675dSTing-Kang Chang		},
701*e7b1675dSTing-Kang Chang		{
702*e7b1675dSTing-Kang Chang			tag:  "json with `expiration` timestamp claim greater than valid JWT max time fails",
703*e7b1675dSTing-Kang Chang			json: `{"exp": 253402301799}`,
704*e7b1675dSTing-Kang Chang		},
705*e7b1675dSTing-Kang Chang		{
706*e7b1675dSTing-Kang Chang			tag:  "json with `not before` timestamp claim smaller than valid JWT min time fails",
707*e7b1675dSTing-Kang Chang			json: `{"nbf": -4}`,
708*e7b1675dSTing-Kang Chang		},
709*e7b1675dSTing-Kang Chang		{
710*e7b1675dSTing-Kang Chang			tag:  "json with `issued at` timestamp claim smaller than valid JWT min time fails",
711*e7b1675dSTing-Kang Chang			json: `{"iat": -4}`,
712*e7b1675dSTing-Kang Chang		},
713*e7b1675dSTing-Kang Chang		{
714*e7b1675dSTing-Kang Chang			tag:  "json with `expiration` timestamp claim smaller than valid JWT min time fails",
715*e7b1675dSTing-Kang Chang			json: `{"exp": -4}`,
716*e7b1675dSTing-Kang Chang		},
717*e7b1675dSTing-Kang Chang		{
718*e7b1675dSTing-Kang Chang			tag:  "json with `not before` claim of non numeric type fails",
719*e7b1675dSTing-Kang Chang			json: `{"nbf": "invalid"}`,
720*e7b1675dSTing-Kang Chang		},
721*e7b1675dSTing-Kang Chang		{
722*e7b1675dSTing-Kang Chang			tag:  "json with `issued at` claim of non numeric type fails",
723*e7b1675dSTing-Kang Chang			json: `{"iat": "invalid"}`,
724*e7b1675dSTing-Kang Chang		},
725*e7b1675dSTing-Kang Chang		{
726*e7b1675dSTing-Kang Chang			tag:  "json with `expiration` claim of non numeric type fails",
727*e7b1675dSTing-Kang Chang			json: `{"exp": "invalid"}`,
728*e7b1675dSTing-Kang Chang		},
729*e7b1675dSTing-Kang Chang	}
730*e7b1675dSTing-Kang Chang
731*e7b1675dSTing-Kang Chang	for _, tc := range testCases {
732*e7b1675dSTing-Kang Chang		t.Run(tc.tag, func(t *testing.T) {
733*e7b1675dSTing-Kang Chang			if _, err := jwt.NewRawJWTFromJSON(nil, []byte(tc.json)); err == nil {
734*e7b1675dSTing-Kang Chang				t.Errorf("expected error instead got nil")
735*e7b1675dSTing-Kang Chang			}
736*e7b1675dSTing-Kang Chang		})
737*e7b1675dSTing-Kang Chang	}
738*e7b1675dSTing-Kang Chang}
739*e7b1675dSTing-Kang Chang
740*e7b1675dSTing-Kang Changfunc TestHasCustomClaimsOfKind(t *testing.T) {
741*e7b1675dSTing-Kang Chang	opts := &jwt.RawJWTOptions{
742*e7b1675dSTing-Kang Chang		TypeHeader:        refString("typeHeader"),
743*e7b1675dSTing-Kang Chang		WithoutExpiration: true,
744*e7b1675dSTing-Kang Chang		CustomClaims: map[string]interface{}{
745*e7b1675dSTing-Kang Chang			"cc-num":    1.67,
746*e7b1675dSTing-Kang Chang			"cc-bool":   false,
747*e7b1675dSTing-Kang Chang			"cc-nil":    nil,
748*e7b1675dSTing-Kang Chang			"cc-list":   []interface{}{1.0, 2.0, 3.0},
749*e7b1675dSTing-Kang Chang			"cc-string": "cc-val",
750*e7b1675dSTing-Kang Chang			"cc-object": map[string]interface{}{
751*e7b1675dSTing-Kang Chang				"nested-cc-num": 5.5,
752*e7b1675dSTing-Kang Chang			},
753*e7b1675dSTing-Kang Chang		},
754*e7b1675dSTing-Kang Chang	}
755*e7b1675dSTing-Kang Chang	token, err := jwt.NewRawJWT(opts)
756*e7b1675dSTing-Kang Chang	if err != nil {
757*e7b1675dSTing-Kang Chang		t.Fatalf("generating valid RawJWT: %v", err)
758*e7b1675dSTing-Kang Chang	}
759*e7b1675dSTing-Kang Chang	if token.HasBooleanClaim("cc-num") {
760*e7b1675dSTing-Kang Chang		t.Errorf("custom number claim 'cc-num' should return false when queried for another type")
761*e7b1675dSTing-Kang Chang	}
762*e7b1675dSTing-Kang Chang	if token.HasNullClaim("cc-bool") {
763*e7b1675dSTing-Kang Chang		t.Errorf("custom boolean claim 'cc-bool' should return false when queried for another type")
764*e7b1675dSTing-Kang Chang	}
765*e7b1675dSTing-Kang Chang	if token.HasNumberClaim("cc-bool") {
766*e7b1675dSTing-Kang Chang		t.Errorf("custom boolean claim 'cc-bool' should return false when queried for another type")
767*e7b1675dSTing-Kang Chang	}
768*e7b1675dSTing-Kang Chang	if token.HasStringClaim("cc-bool") {
769*e7b1675dSTing-Kang Chang		t.Errorf("custom boolean claim 'cc-bool' should return false when queried for another type")
770*e7b1675dSTing-Kang Chang	}
771*e7b1675dSTing-Kang Chang	if token.HasArrayClaim("cc-bool") {
772*e7b1675dSTing-Kang Chang		t.Errorf("custom boolean claim 'cc-bool' should return false when queried for another type")
773*e7b1675dSTing-Kang Chang	}
774*e7b1675dSTing-Kang Chang	if token.HasObjectClaim("cc-bool") {
775*e7b1675dSTing-Kang Chang		t.Errorf("custom boolean claim 'cc-bool' should return false when queried for another type")
776*e7b1675dSTing-Kang Chang	}
777*e7b1675dSTing-Kang Chang}
778*e7b1675dSTing-Kang Chang
779*e7b1675dSTing-Kang Changfunc TestGettingRegisteredClaimsThroughCustomFails(t *testing.T) {
780*e7b1675dSTing-Kang Chang	opts := &jwt.RawJWTOptions{
781*e7b1675dSTing-Kang Chang		TypeHeader: refString("typeHeader"),
782*e7b1675dSTing-Kang Chang		Subject:    refString("tink-test-subject"),
783*e7b1675dSTing-Kang Chang		Issuer:     refString("tink-test-issuer"),
784*e7b1675dSTing-Kang Chang		JWTID:      refString("tink-jwt-id-1"),
785*e7b1675dSTing-Kang Chang		Audiences:  []string{"aud-1", "aud-2"},
786*e7b1675dSTing-Kang Chang		ExpiresAt:  refTime(validExpiration),
787*e7b1675dSTing-Kang Chang		IssuedAt:   refTime(validExpiration - 100),
788*e7b1675dSTing-Kang Chang		NotBefore:  refTime(validExpiration - 50),
789*e7b1675dSTing-Kang Chang	}
790*e7b1675dSTing-Kang Chang	token, err := jwt.NewRawJWT(opts)
791*e7b1675dSTing-Kang Chang	if err != nil {
792*e7b1675dSTing-Kang Chang		t.Fatalf("generating valid RawJWT: %v", err)
793*e7b1675dSTing-Kang Chang	}
794*e7b1675dSTing-Kang Chang	if !cmp.Equal(token.CustomClaimNames(), []string{}) {
795*e7b1675dSTing-Kang Chang		t.Errorf("tc.token.CustomClaimNames() = %q want %q", token.CustomClaimNames(), []string{})
796*e7b1675dSTing-Kang Chang	}
797*e7b1675dSTing-Kang Chang	for _, c := range []string{"sub", "iss", "aud", "nbf", "exp", "iat", "jti"} {
798*e7b1675dSTing-Kang Chang		if token.HasNullClaim(c) {
799*e7b1675dSTing-Kang Chang			t.Errorf("registered '%q' claim should return false when calling HasNullClaim", c)
800*e7b1675dSTing-Kang Chang		}
801*e7b1675dSTing-Kang Chang		if token.HasBooleanClaim(c) {
802*e7b1675dSTing-Kang Chang			t.Errorf("registered '%q' claim should return false when calling HasBooleanClaim", c)
803*e7b1675dSTing-Kang Chang		}
804*e7b1675dSTing-Kang Chang		if _, err := token.BooleanClaim(c); err == nil {
805*e7b1675dSTing-Kang Chang			t.Errorf("expected error when calling token.BoolClaim(%q) instead got nil", c)
806*e7b1675dSTing-Kang Chang		}
807*e7b1675dSTing-Kang Chang		if token.HasNumberClaim(c) {
808*e7b1675dSTing-Kang Chang			t.Errorf("registered '%q' claim should return false when calling HasNumberClaim", c)
809*e7b1675dSTing-Kang Chang		}
810*e7b1675dSTing-Kang Chang		if _, err := token.NumberClaim(c); err == nil {
811*e7b1675dSTing-Kang Chang			t.Errorf("expected error when calling token.NumberClaim(%q) instead got nil", c)
812*e7b1675dSTing-Kang Chang		}
813*e7b1675dSTing-Kang Chang		if token.HasStringClaim(c) {
814*e7b1675dSTing-Kang Chang			t.Errorf("registered '%q' claim should return false when calling HasStringClaim", c)
815*e7b1675dSTing-Kang Chang		}
816*e7b1675dSTing-Kang Chang		if _, err := token.StringClaim(c); err == nil {
817*e7b1675dSTing-Kang Chang			t.Errorf("expected error when calling token.StringClaim(%q) instead got nil", c)
818*e7b1675dSTing-Kang Chang		}
819*e7b1675dSTing-Kang Chang		if token.HasArrayClaim(c) {
820*e7b1675dSTing-Kang Chang			t.Errorf("registered '%q' claim should return false when calling HasArrayClaim", c)
821*e7b1675dSTing-Kang Chang		}
822*e7b1675dSTing-Kang Chang		if _, err := token.ArrayClaim(c); err == nil {
823*e7b1675dSTing-Kang Chang			t.Errorf("expected error when calling token.ListClaim(%q) instead got nil", c)
824*e7b1675dSTing-Kang Chang		}
825*e7b1675dSTing-Kang Chang		if token.HasObjectClaim(c) {
826*e7b1675dSTing-Kang Chang			t.Errorf("registered '%q' claim should return false when calling HasObjectClaim", c)
827*e7b1675dSTing-Kang Chang		}
828*e7b1675dSTing-Kang Chang		if _, err := token.ObjectClaim(c); err == nil {
829*e7b1675dSTing-Kang Chang			t.Errorf("expected error when calling token.JSONClaim(%q) instead got nil", c)
830*e7b1675dSTing-Kang Chang		}
831*e7b1675dSTing-Kang Chang	}
832*e7b1675dSTing-Kang Chang}
833