diff --git a/server/invitation_test.go b/server/invitation_test.go index 4481914d..f75ebaea 100644 --- a/server/invitation_test.go +++ b/server/invitation_test.go @@ -159,9 +159,9 @@ func TestInvitationHandler(t *testing.T) { t.Errorf("case %d: password token is invalid: %v", i, err) } - expTime := pwrReset.Claims["exp"].(float64) - if expTime > float64(tZero.Add(handler.redirectValidityWindow).Unix()) || - expTime < float64(tZero.Unix()) { + expTime := pwrReset.Claims["exp"].(int64) + if expTime > tZero.Add(handler.redirectValidityWindow).Unix() || + expTime < tZero.Unix() { t.Errorf("case %d: funny expiration time detected: %d", i, pwrReset.Claims["exp"]) } diff --git a/session/session_test.go b/session/session_test.go index 744cb90f..2dae3ddf 100644 --- a/session/session_test.go +++ b/session/session_test.go @@ -34,8 +34,8 @@ func TestSessionClaims(t *testing.T) { "iss": issuerURL, "sub": "elroy-id", "aud": "XXX", - "iat": float64(now.Unix()), - "exp": float64(now.Add(time.Hour).Unix()), + "iat": now.Unix(), + "exp": now.Add(time.Hour).Unix(), }, }, @@ -57,8 +57,8 @@ func TestSessionClaims(t *testing.T) { "iss": issuerURL, "sub": "elroy-id", "aud": "XXX", - "iat": float64(now.Unix()), - "exp": float64(now.Add(time.Hour).Unix()), + "iat": now.Unix(), + "exp": now.Add(time.Hour).Unix(), }, }, // Nonce gets propagated. @@ -79,8 +79,8 @@ func TestSessionClaims(t *testing.T) { "iss": issuerURL, "sub": "elroy-id", "aud": "XXX", - "iat": float64(now.Unix()), - "exp": float64(now.Add(time.Hour).Unix()), + "iat": now.Unix(), + "exp": now.Add(time.Hour).Unix(), "nonce": "oncenay", }, }, diff --git a/user/email_verification_test.go b/user/email_verification_test.go index 3cfdc97b..d667d3c3 100644 --- a/user/email_verification_test.go +++ b/user/email_verification_test.go @@ -45,9 +45,9 @@ func TestNewEmailVerification(t *testing.T) { "aud": clientID, ClaimEmailVerificationCallback: callback, ClaimEmailVerificationEmail: usr.Email, - "exp": float64(now.Add(expires).Unix()), + "exp": now.Add(expires).Unix(), "sub": usr.ID, - "iat": float64(now.Unix()), + "iat": now.Unix(), }, }, } diff --git a/user/password_test.go b/user/password_test.go index 0f81544f..68bbbc8f 100644 --- a/user/password_test.go +++ b/user/password_test.go @@ -106,9 +106,9 @@ func TestNewPasswordReset(t *testing.T) { "aud": clientID, ClaimPasswordResetCallback: callback, ClaimPasswordResetPassword: string(password), - "exp": float64(now.Add(expires).Unix()), + "exp": now.Add(expires).Unix(), "sub": usr.ID, - "iat": float64(now.Unix()), + "iat": now.Unix(), }, }, } diff --git a/user/user.go b/user/user.go index 1737750b..4b36b6b9 100644 --- a/user/user.go +++ b/user/user.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "math" "time" "net/mail" @@ -259,5 +260,27 @@ func parseAndVerifyTokenClaims(token string, issuer url.URL, keys []key.PublicKe return TokenClaims{}, err } + timeClaimsToInt(claims) + return TokenClaims{claims}, nil } + +// timeClaimsToInt converts float64 time claims to ints. +// This is unfortunately neccessary for interop as some clients incorrectly fail +// to marshal floats as times. +func timeClaimsToInt(claims jose.Claims) { + for _, k := range []string{"exp", "iat"} { + v, ok := claims[k] + if !ok { + continue + } + + fVal, ok := v.(float64) + if !ok { + continue + } + + // round + claims[k] = int64(fVal + math.Copysign(0.5, fVal)) + } +}