github.com/lestrrat-go/jwx/v2@v2.0.21/jwt/openid/openid_test.go (about)

     1  package openid_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strconv"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/lestrrat-go/jwx/v2/internal/json"
    11  	"github.com/lestrrat-go/jwx/v2/internal/jwxtest"
    12  
    13  	"github.com/lestrrat-go/jwx/v2/jwa"
    14  	"github.com/lestrrat-go/jwx/v2/jwt"
    15  	"github.com/lestrrat-go/jwx/v2/jwt/internal/types"
    16  	"github.com/lestrrat-go/jwx/v2/jwt/openid"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  const aLongLongTimeAgo = 233431200
    22  const aLongLongTimeAgoString = "233431200"
    23  const (
    24  	tokenTime = 233431200
    25  )
    26  
    27  var expectedTokenTime = time.Unix(tokenTime, 0).UTC()
    28  
    29  func testStockAddressClaim(t *testing.T, x *openid.AddressClaim) {
    30  	t.Helper()
    31  	if !assert.NotNil(t, x) {
    32  		return
    33  	}
    34  
    35  	tests := []struct {
    36  		Accessor func() string
    37  		KeyName  string
    38  		Value    string
    39  	}{
    40  		{
    41  			Accessor: x.Formatted,
    42  			KeyName:  openid.AddressFormattedKey,
    43  			Value:    "〒105-0011 東京都港区芝公園4丁目2−8",
    44  		},
    45  		{
    46  			Accessor: x.Country,
    47  			KeyName:  openid.AddressCountryKey,
    48  			Value:    "日本",
    49  		},
    50  		{
    51  			Accessor: x.Region,
    52  			KeyName:  openid.AddressRegionKey,
    53  			Value:    "東京都",
    54  		},
    55  		{
    56  			Accessor: x.Locality,
    57  			KeyName:  openid.AddressLocalityKey,
    58  			Value:    "港区",
    59  		},
    60  		{
    61  			Accessor: x.StreetAddress,
    62  			KeyName:  openid.AddressStreetAddressKey,
    63  			Value:    "芝公園4丁目2−8",
    64  		},
    65  		{
    66  			Accessor: x.PostalCode,
    67  			KeyName:  openid.AddressPostalCodeKey,
    68  			Value:    "105-0011",
    69  		},
    70  	}
    71  
    72  	for _, tc := range tests {
    73  		tc := tc
    74  		t.Run(tc.KeyName, func(t *testing.T) {
    75  			t.Run("Accessor", func(t *testing.T) {
    76  				if !assert.Equal(t, tc.Value, tc.Accessor(), "values should match") {
    77  					return
    78  				}
    79  			})
    80  			t.Run("Get", func(t *testing.T) {
    81  				v, ok := x.Get(tc.KeyName)
    82  				if !assert.True(t, ok, `x.Get should succeed`) {
    83  					return
    84  				}
    85  				if !assert.Equal(t, tc.Value, v, `values should match`) {
    86  					return
    87  				}
    88  			})
    89  		})
    90  	}
    91  }
    92  
    93  func TestAdressClaim(t *testing.T) {
    94  	const src = `{
    95      "formatted": "〒105-0011 東京都港区芝公園4丁目2−8",
    96  		"street_address": "芝公園4丁目2−8",
    97  		"locality": "港区",
    98  		"region": "東京都",
    99  		"postal_code": "105-0011",
   100  		"country": "日本"
   101  	}`
   102  
   103  	var address openid.AddressClaim
   104  	if !assert.NoError(t, json.Unmarshal([]byte(src), &address), "json.Unmarshal should succeed") {
   105  		return
   106  	}
   107  
   108  	var roundtrip openid.AddressClaim
   109  	buf, err := json.Marshal(address)
   110  	if !assert.NoError(t, err, `json.Marshal(address) should succeed`) {
   111  		return
   112  	}
   113  
   114  	if !assert.NoError(t, json.Unmarshal(buf, &roundtrip), "json.Unmarshal should succeed") {
   115  		return
   116  	}
   117  
   118  	for _, x := range []*openid.AddressClaim{&address, &roundtrip} {
   119  		testStockAddressClaim(t, x)
   120  	}
   121  }
   122  
   123  func TestOpenIDClaims(t *testing.T) {
   124  	getVerify := func(token openid.Token, key string, expected interface{}) bool {
   125  		v, ok := token.Get(key)
   126  		if !assert.True(t, ok, `token.Get %#v should succeed`, key) {
   127  			return false
   128  		}
   129  		return assert.Equal(t, v, expected)
   130  	}
   131  
   132  	var base = []struct {
   133  		Value    interface{}
   134  		Expected func(interface{}) interface{}
   135  		Check    func(openid.Token)
   136  		Key      string
   137  	}{
   138  		{
   139  			Key:   openid.AudienceKey,
   140  			Value: []string{"developers", "secops", "tac"},
   141  			Check: func(token openid.Token) {
   142  				assert.Equal(t, token.Audience(), []string{"developers", "secops", "tac"})
   143  			},
   144  		},
   145  		{
   146  			Key:   openid.ExpirationKey,
   147  			Value: tokenTime,
   148  			Expected: func(v interface{}) interface{} {
   149  				var n types.NumericDate
   150  				if err := n.Accept(v); err != nil {
   151  					panic(err)
   152  				}
   153  				return n.Get()
   154  			},
   155  			Check: func(token openid.Token) {
   156  				assert.Equal(t, token.Expiration(), expectedTokenTime)
   157  			},
   158  		},
   159  		{
   160  			Key:   openid.IssuedAtKey,
   161  			Value: tokenTime,
   162  			Expected: func(v interface{}) interface{} {
   163  				var n types.NumericDate
   164  				if err := n.Accept(v); err != nil {
   165  					panic(err)
   166  				}
   167  				return n.Get()
   168  			},
   169  			Check: func(token openid.Token) {
   170  				assert.Equal(t, token.Expiration(), expectedTokenTime)
   171  			},
   172  		},
   173  		{
   174  			Key:   openid.IssuerKey,
   175  			Value: "http://www.example.com",
   176  			Check: func(token openid.Token) {
   177  				assert.Equal(t, token.Issuer(), "http://www.example.com")
   178  			},
   179  		},
   180  		{
   181  			Key:   openid.JwtIDKey,
   182  			Value: "e9bc097a-ce51-4036-9562-d2ade882db0d",
   183  			Check: func(token openid.Token) {
   184  				assert.Equal(t, token.JwtID(), "e9bc097a-ce51-4036-9562-d2ade882db0d")
   185  			},
   186  		},
   187  		{
   188  			Key:   openid.NotBeforeKey,
   189  			Value: tokenTime,
   190  			Expected: func(v interface{}) interface{} {
   191  				var n types.NumericDate
   192  				if err := n.Accept(v); err != nil {
   193  					panic(err)
   194  				}
   195  				return n.Get()
   196  			},
   197  			Check: func(token openid.Token) {
   198  				assert.Equal(t, token.NotBefore(), expectedTokenTime)
   199  			},
   200  		},
   201  		{
   202  			Key:   openid.SubjectKey,
   203  			Value: "unit test",
   204  			Check: func(token openid.Token) {
   205  				assert.Equal(t, token.Subject(), "unit test")
   206  			},
   207  		},
   208  		{
   209  			Value: "jwx",
   210  			Key:   openid.NameKey,
   211  			Check: func(token openid.Token) {
   212  				assert.Equal(t, token.Name(), "jwx")
   213  			},
   214  		},
   215  		{
   216  			Value: "jay",
   217  			Key:   openid.GivenNameKey,
   218  			Check: func(token openid.Token) {
   219  				assert.Equal(t, token.GivenName(), "jay")
   220  			},
   221  		},
   222  		{
   223  			Value: "weee",
   224  			Key:   openid.MiddleNameKey,
   225  			Check: func(token openid.Token) {
   226  				assert.Equal(t, token.MiddleName(), "weee")
   227  			},
   228  		},
   229  		{
   230  			Value: "xi",
   231  			Key:   openid.FamilyNameKey,
   232  			Check: func(token openid.Token) {
   233  				assert.Equal(t, token.FamilyName(), "xi")
   234  			},
   235  		},
   236  		{
   237  			Value: "jayweexi",
   238  			Key:   openid.NicknameKey,
   239  			Check: func(token openid.Token) {
   240  				assert.Equal(t, token.Nickname(), "jayweexi")
   241  			},
   242  		},
   243  		{
   244  			Value: "jwx",
   245  			Key:   openid.PreferredUsernameKey,
   246  			Check: func(token openid.Token) {
   247  				assert.Equal(t, token.PreferredUsername(), "jwx")
   248  			},
   249  		},
   250  		{
   251  			Value: "https://github.com/lestrrat-go/jwx/v2",
   252  			Key:   openid.ProfileKey,
   253  			Check: func(token openid.Token) {
   254  				assert.Equal(t, token.Profile(), "https://github.com/lestrrat-go/jwx/v2")
   255  			},
   256  		},
   257  		{
   258  			Value: "https://avatars1.githubusercontent.com/u/36653903?s=400&v=4",
   259  			Key:   openid.PictureKey,
   260  			Check: func(token openid.Token) {
   261  				assert.Equal(t, token.Picture(), "https://avatars1.githubusercontent.com/u/36653903?s=400&v=4")
   262  			},
   263  		},
   264  		{
   265  			Value: "https://github.com/lestrrat-go/jwx/v2",
   266  			Key:   openid.WebsiteKey,
   267  			Check: func(token openid.Token) {
   268  				assert.Equal(t, token.Website(), "https://github.com/lestrrat-go/jwx/v2")
   269  			},
   270  		},
   271  		{
   272  			Value: "lestrrat+github@gmail.com",
   273  			Key:   openid.EmailKey,
   274  			Check: func(token openid.Token) {
   275  				assert.Equal(t, token.Email(), "lestrrat+github@gmail.com")
   276  			},
   277  		},
   278  		{
   279  			Value: true,
   280  			Key:   openid.EmailVerifiedKey,
   281  			Check: func(token openid.Token) {
   282  				assert.True(t, token.EmailVerified())
   283  			},
   284  		},
   285  		{
   286  			Value: "n/a",
   287  			Key:   openid.GenderKey,
   288  			Check: func(token openid.Token) {
   289  				assert.Equal(t, token.Gender(), "n/a")
   290  			},
   291  		},
   292  		{
   293  			Value: "2015-11-04",
   294  			Key:   openid.BirthdateKey,
   295  			Expected: func(v interface{}) interface{} {
   296  				var b openid.BirthdateClaim
   297  				if err := b.Accept(v); err != nil {
   298  					panic(err)
   299  				}
   300  				return &b
   301  			},
   302  			Check: func(token openid.Token) {
   303  				var b openid.BirthdateClaim
   304  				b.Accept("2015-11-04")
   305  				assert.Equal(t, token.Birthdate(), &b)
   306  			},
   307  		},
   308  		{
   309  			Value: "Asia/Tokyo",
   310  			Key:   openid.ZoneinfoKey,
   311  			Check: func(token openid.Token) {
   312  				assert.Equal(t, token.Zoneinfo(), "Asia/Tokyo")
   313  			},
   314  		},
   315  		{
   316  			Value: "ja_JP",
   317  			Key:   openid.LocaleKey,
   318  			Check: func(token openid.Token) {
   319  				assert.Equal(t, token.Locale(), "ja_JP")
   320  			},
   321  		},
   322  		{
   323  			Value: "819012345678",
   324  			Key:   openid.PhoneNumberKey,
   325  			Check: func(token openid.Token) {
   326  				assert.Equal(t, token.PhoneNumber(), "819012345678")
   327  			},
   328  		},
   329  		{
   330  			Value: true,
   331  			Key:   openid.PhoneNumberVerifiedKey,
   332  			Check: func(token openid.Token) {
   333  				assert.True(t, token.PhoneNumberVerified())
   334  			},
   335  		},
   336  		{
   337  			Value: map[string]interface{}{
   338  				"formatted":      "〒105-0011 東京都港区芝公園4丁目2−8",
   339  				"street_address": "芝公園4丁目2−8",
   340  				"locality":       "港区",
   341  				"region":         "東京都",
   342  				"country":        "日本",
   343  				"postal_code":    "105-0011",
   344  			},
   345  			Key: openid.AddressKey,
   346  			Expected: func(v interface{}) interface{} {
   347  				address := openid.NewAddress()
   348  				m, ok := v.(map[string]interface{})
   349  				if !ok {
   350  					panic(fmt.Sprintf("expected map[string]interface{}, got %T", v))
   351  				}
   352  				for name, val := range m {
   353  					if !assert.NoError(t, address.Set(name, val), `address.Set should succeed`) {
   354  						return nil
   355  					}
   356  				}
   357  				return address
   358  			},
   359  			Check: func(token openid.Token) {
   360  				testStockAddressClaim(t, token.Address())
   361  			},
   362  		},
   363  		{
   364  			Value: aLongLongTimeAgoString,
   365  			Key:   openid.UpdatedAtKey,
   366  			Expected: func(v interface{}) interface{} {
   367  				var n types.NumericDate
   368  				if err := n.Accept(v); err != nil {
   369  					panic(err)
   370  				}
   371  				return n.Get()
   372  			},
   373  			Check: func(token openid.Token) {
   374  				assert.Equal(t, time.Unix(aLongLongTimeAgo, 0).UTC(), token.UpdatedAt())
   375  			},
   376  		},
   377  		{
   378  			Value: `dummy`,
   379  			Key:   `dummy`,
   380  			Check: func(token openid.Token) {
   381  				v, ok := token.Get(`dummy`)
   382  				if !assert.True(t, ok, `token.Get should return valid value`) {
   383  					return
   384  				}
   385  				if !assert.Equal(t, `dummy`, v, `values should match`) {
   386  					return
   387  				}
   388  			},
   389  		},
   390  	}
   391  
   392  	var data = map[string]interface{}{}
   393  	var expected = map[string]interface{}{}
   394  	for _, value := range base {
   395  		data[value.Key] = value.Value
   396  		if expf := value.Expected; expf != nil {
   397  			expected[value.Key] = expf(value.Value)
   398  		} else {
   399  			expected[value.Key] = value.Value
   400  		}
   401  	}
   402  
   403  	type openidTokTestCase struct {
   404  		Token openid.Token
   405  		Name  string
   406  	}
   407  	var tokens []openidTokTestCase
   408  
   409  	{ // one with Set()
   410  		b := openid.NewBuilder()
   411  		for name, value := range data {
   412  			b.Claim(name, value)
   413  		}
   414  		token, err := b.Build()
   415  		if !assert.NoError(t, err, `b.Build() should succeed`) {
   416  			return
   417  		}
   418  		tokens = append(tokens, openidTokTestCase{Name: `token constructed by calling Set()`, Token: token})
   419  	}
   420  
   421  	{ // two with json.Marshal / json.Unmarshal
   422  		src, err := json.MarshalIndent(data, "", "  ")
   423  		if !assert.NoError(t, err, `failed to marshal base map`) {
   424  			return
   425  		}
   426  
   427  		t.Logf("Using source JSON: %s", src)
   428  
   429  		token := openid.New()
   430  		if !assert.NoError(t, json.Unmarshal(src, &token), `json.Unmarshal should succeed`) {
   431  			return
   432  		}
   433  		tokens = append(tokens, openidTokTestCase{Name: `token constructed by Marshal(map)+Unmashal`, Token: token})
   434  
   435  		// One more... Marshal the token, _and_ re-unmarshal
   436  		buf, err := json.Marshal(token)
   437  		if !assert.NoError(t, err, `json.Marshal should succeed`) {
   438  			return
   439  		}
   440  
   441  		token2 := openid.New()
   442  		if !assert.NoError(t, json.Unmarshal(buf, &token2), `json.Unmarshal should succeed`) {
   443  			return
   444  		}
   445  		tokens = append(tokens, openidTokTestCase{Name: `token constructed by Marshal(openid.Token)+Unmashal`, Token: token2})
   446  
   447  		// Sign it, and use jwt.Parse
   448  
   449  		var token3 openid.Token
   450  		{
   451  			alg := jwa.RS256
   452  			key, err := jwxtest.GenerateRsaKey()
   453  			if !assert.NoError(t, err, `rsa.GeneraKey should succeed`) {
   454  				return
   455  			}
   456  			signed, err := jwt.Sign(token, jwt.WithKey(alg, key))
   457  			if !assert.NoError(t, err, `jwt.Sign should succeed`) {
   458  				return
   459  			}
   460  
   461  			tokenTmp, err := jwt.Parse(signed, jwt.WithToken(openid.New()), jwt.WithKey(alg, &key.PublicKey), jwt.WithValidate(false))
   462  			if !assert.NoError(t, err, `parsing the token via jwt.Parse should succeed`) {
   463  				return
   464  			}
   465  
   466  			// Check if token is an OpenID token
   467  			if _, ok := tokenTmp.(openid.Token); !assert.True(t, ok, `token should be a openid.Token (%T)`, tokenTmp) {
   468  				return
   469  			}
   470  			token3 = tokenTmp.(openid.Token)
   471  		}
   472  
   473  		tokens = append(tokens, openidTokTestCase{Name: `token constructed by jwt.Parse`, Token: token3})
   474  	}
   475  
   476  	for _, token := range tokens {
   477  		token := token
   478  		t.Run(token.Name, func(t *testing.T) {
   479  			for _, value := range base {
   480  				value := value
   481  				t.Run(value.Key, func(t *testing.T) {
   482  					value.Check(token.Token)
   483  				})
   484  				t.Run(value.Key+" via Get()", func(t *testing.T) {
   485  					expected := value.Value
   486  					if expf := value.Expected; expf != nil {
   487  						expected = expf(value.Value)
   488  					}
   489  					getVerify(token.Token, value.Key, expected)
   490  				})
   491  			}
   492  		})
   493  	}
   494  
   495  	t.Run("Iterator", func(t *testing.T) {
   496  		v := tokens[0].Token
   497  		t.Run("Iterate", func(t *testing.T) {
   498  			seen := make(map[string]interface{})
   499  			for iter := v.Iterate(context.TODO()); iter.Next(context.TODO()); {
   500  				pair := iter.Pair()
   501  				seen[pair.Key.(string)] = pair.Value
   502  
   503  				getV, ok := v.Get(pair.Key.(string))
   504  				if !assert.True(t, ok, `v.Get should succeed for key %#v`, pair.Key) {
   505  					return
   506  				}
   507  				if !assert.Equal(t, pair.Value, getV, `pair.Value should match value from v.Get()`) {
   508  					return
   509  				}
   510  			}
   511  			if !assert.Equal(t, expected, seen, `values should match`) {
   512  				return
   513  			}
   514  		})
   515  		t.Run("Walk", func(t *testing.T) {
   516  			seen := make(map[string]interface{})
   517  			v.Walk(context.TODO(), openid.VisitorFunc(func(key string, value interface{}) error {
   518  				seen[key] = value
   519  				return nil
   520  			}))
   521  			if !assert.Equal(t, expected, seen, `values should match`) {
   522  				return
   523  			}
   524  		})
   525  		t.Run("AsMap", func(t *testing.T) {
   526  			seen, err := v.AsMap(context.TODO())
   527  			if !assert.NoError(t, err, `v.AsMap should succeed`) {
   528  				return
   529  			}
   530  			if !assert.Equal(t, expected, seen, `values should match`) {
   531  				return
   532  			}
   533  		})
   534  		t.Run("Clone", func(t *testing.T) {
   535  			cloned, err := v.Clone()
   536  			if !assert.NoError(t, err, `v.Clone should succeed`) {
   537  				return
   538  			}
   539  
   540  			if !assert.True(t, jwt.Equal(v, cloned), `values should match`) {
   541  				return
   542  			}
   543  		})
   544  	})
   545  }
   546  
   547  func TestBirthdateClaim(t *testing.T) {
   548  	t.Parallel()
   549  	t.Run("regular date", func(t *testing.T) {
   550  		t.Parallel()
   551  		testcases := []struct {
   552  			Source string
   553  			Year   int
   554  			Month  int
   555  			Day    int
   556  			Error  bool
   557  		}{
   558  			{
   559  				Source: `"2015-11-04"`,
   560  				Year:   2015,
   561  				Month:  11,
   562  				Day:    4,
   563  			},
   564  			{
   565  				Source: `"0009-09-09"`,
   566  				Year:   9,
   567  				Month:  9,
   568  				Day:    9,
   569  			},
   570  			{
   571  				Source: `{}`,
   572  				Error:  true,
   573  			},
   574  			{
   575  				Source: `"202X-01-01"`,
   576  				Error:  true,
   577  			},
   578  			{
   579  				Source: `"0000-01-01"`,
   580  				Error:  true,
   581  			},
   582  			{
   583  				Source: `"0001-00-01"`,
   584  				Error:  true,
   585  			},
   586  			{
   587  				Source: `"0001-01-00"`,
   588  				Error:  true,
   589  			},
   590  		}
   591  
   592  		for _, tc := range testcases {
   593  			tc := tc
   594  			t.Run(tc.Source, func(t *testing.T) {
   595  				var b openid.BirthdateClaim
   596  				if tc.Error {
   597  					assert.Error(t, json.Unmarshal([]byte(tc.Source), &b), `json.Unmarshal should fail`)
   598  					return
   599  				}
   600  
   601  				if !assert.NoError(t, json.Unmarshal([]byte(tc.Source), &b), `json.Unmarshal should succeed`) {
   602  					return
   603  				}
   604  
   605  				if !assert.Equal(t, b.Year(), tc.Year, "year should match") {
   606  					return
   607  				}
   608  				if !assert.Equal(t, b.Month(), tc.Month, "month should match") {
   609  					return
   610  				}
   611  				if !assert.Equal(t, b.Day(), tc.Day, "day should match") {
   612  					return
   613  				}
   614  				serialized, err := json.Marshal(b)
   615  				if !assert.NoError(t, err, `json.Marshal should succeed`) {
   616  					return
   617  				}
   618  				if !assert.Equal(t, string(serialized), tc.Source, `serialized format should be the same`) {
   619  					return
   620  				}
   621  				stringified := b.String()
   622  				expectedString, _ := strconv.Unquote(tc.Source)
   623  				if !assert.Equal(t, stringified, expectedString, `stringified format should be the same`) {
   624  					return
   625  				}
   626  			})
   627  		}
   628  	})
   629  	t.Run("empty date", func(t *testing.T) {
   630  		t.Parallel()
   631  		var b openid.BirthdateClaim
   632  		if !assert.Equal(t, b.Year(), 0, "year should match") {
   633  			return
   634  		}
   635  		if !assert.Equal(t, b.Month(), 0, "month should match") {
   636  			return
   637  		}
   638  		if !assert.Equal(t, b.Day(), 0, "day should match") {
   639  			return
   640  		}
   641  	})
   642  	t.Run("invalid accept", func(t *testing.T) {
   643  		t.Parallel()
   644  		var b openid.BirthdateClaim
   645  		if !assert.Error(t, b.Accept(nil)) {
   646  			return
   647  		}
   648  	})
   649  }
   650  
   651  func TestKeys(t *testing.T) {
   652  	at := assert.New(t)
   653  	at.Equal(`address`, openid.AddressKey)
   654  	at.Equal(`aud`, openid.AudienceKey)
   655  	at.Equal(`birthdate`, openid.BirthdateKey)
   656  	at.Equal(`email`, openid.EmailKey)
   657  	at.Equal(`email_verified`, openid.EmailVerifiedKey)
   658  	at.Equal(`exp`, openid.ExpirationKey)
   659  	at.Equal(`family_name`, openid.FamilyNameKey)
   660  	at.Equal(`gender`, openid.GenderKey)
   661  	at.Equal(`given_name`, openid.GivenNameKey)
   662  	at.Equal(`iat`, openid.IssuedAtKey)
   663  	at.Equal(`iss`, openid.IssuerKey)
   664  	at.Equal(`jti`, openid.JwtIDKey)
   665  	at.Equal(`locale`, openid.LocaleKey)
   666  	at.Equal(`middle_name`, openid.MiddleNameKey)
   667  	at.Equal(`name`, openid.NameKey)
   668  	at.Equal(`nickname`, openid.NicknameKey)
   669  	at.Equal(`nbf`, openid.NotBeforeKey)
   670  	at.Equal(`phone_number`, openid.PhoneNumberKey)
   671  	at.Equal(`phone_number_verified`, openid.PhoneNumberVerifiedKey)
   672  	at.Equal(`picture`, openid.PictureKey)
   673  	at.Equal(`preferred_username`, openid.PreferredUsernameKey)
   674  	at.Equal(`profile`, openid.ProfileKey)
   675  	at.Equal(`sub`, openid.SubjectKey)
   676  	at.Equal(`updated_at`, openid.UpdatedAtKey)
   677  	at.Equal(`website`, openid.WebsiteKey)
   678  	at.Equal(`zoneinfo`, openid.ZoneinfoKey)
   679  }
   680  
   681  func TestGH734(t *testing.T) {
   682  	const src = `{
   683      "nickname": "miniscruff",
   684      "updated_at": "2022-05-06T04:57:24.367Z",
   685      "email_verified": true
   686    }`
   687  
   688  	expected, _ := time.Parse(time.RFC3339, "2022-05-06T04:57:24.367Z")
   689  	for _, pedantic := range []bool{true, false} {
   690  		t.Run(fmt.Sprintf("pedantic=%t", pedantic), func(t *testing.T) {
   691  			jwt.Settings(jwt.WithNumericDateParsePedantic(pedantic))
   692  			tok := openid.New()
   693  			_, err := jwt.Parse(
   694  				[]byte(src),
   695  				jwt.WithToken(tok),
   696  				jwt.WithVerify(false),
   697  				jwt.WithValidate(false),
   698  			)
   699  			if pedantic {
   700  				require.Error(t, err, `jwt.Parse should fail for pedantic parser`)
   701  			} else {
   702  				require.NoError(t, err, `jwt.Parse should succeed`)
   703  				require.Equal(t, expected, tok.UpdatedAt(), `updated_at should match`)
   704  			}
   705  		})
   706  	}
   707  	jwt.Settings(jwt.WithNumericDateParsePedantic(false))
   708  }