Skip to content
This repository has been archived by the owner on Feb 27, 2023. It is now read-only.

Commit

Permalink
jwt.ValidateWithLeeway: Return error if IssuedAt (iat) is in the future
Browse files Browse the repository at this point in the history
Add a check to ValidateWithLeeway that the IssuedAt (iat) field is in the
past. This field is optional, and this check is not required by the RFC,
but seems like a reasonable check. See:
https://tools.ietf.org/html/rfc7519#section-4.1.6

Fixes #216
  • Loading branch information
evanj committed Feb 3, 2019
1 parent 985395e commit 018cad1
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 1 deletion.
5 changes: 4 additions & 1 deletion jwt/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,8 @@ var ErrNotValidYet = errors.New("square/go-jose/jwt: validation failed, token no
// ErrExpired indicates that token is used after expiry time indicated in exp claim.
var ErrExpired = errors.New("square/go-jose/jwt: validation failed, token is expired (exp)")

// ErrInvalidContentType indicated that token requires JWT cty header.
// ErrIssuedInTheFuture indicates that the iat field is in the future.
var ErrIssuedInTheFuture = errors.New("square/go-jsoe/jwt: validation field, token issued in the future (iat)")

// ErrInvalidContentType indicates that token requires JWT cty header.
var ErrInvalidContentType = errors.New("square/go-jose/jwt: expected content type to be JWT (cty header)")
6 changes: 6 additions & 0 deletions jwt/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,11 @@ func (c Claims) ValidateWithLeeway(e Expected, leeway time.Duration) error {
return ErrExpired
}

// IssuedAt is optional but cannot be in the future. This is not required by the RFC, but
// something is misconfigured if this happens and we should not trust it.
if !e.Time.IsZero() && e.Time.Add(leeway).Before(c.IssuedAt.Time()) {
return ErrIssuedInTheFuture
}

return nil
}
36 changes: 36 additions & 0 deletions jwt/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,39 @@ func TestExpiryAndNotBefore(t *testing.T) {
assert.Equal(t, err, ErrNotValidYet)
}
}

func TestIssuedInFuture(t *testing.T) {
now := time.Date(2016, 1, 1, 12, 0, 0, 0, time.UTC)
oneHourInThePast := now.Add(-time.Hour)
oneHourInTheFuture := now.Add(time.Hour)

c := Claims{
IssuedAt: NewNumericDate(now),
NotBefore: NewNumericDate(oneHourInThePast),
Expiry: NewNumericDate(oneHourInTheFuture),
}

// defaults: valid right now, or in the future
assert.NoError(t, c.Validate(Expected{Time: now}))
assert.NoError(t, c.Validate(Expected{Time: now.Add(2 * DefaultLeeway)}))

// cannot be issued in the future
err := c.Validate(Expected{Time: now.Add(-2 * DefaultLeeway)})
if assert.Error(t, err) {
assert.Equal(t, err, ErrIssuedInTheFuture)
}
err = c.Validate(Expected{Time: now.Add(-DefaultLeeway - 1)})
if assert.Error(t, err) {
assert.Equal(t, err, ErrIssuedInTheFuture)
}

// valid when we are within the default leeway
assert.NoError(t, c.Validate(Expected{Time: now.Add(-DefaultLeeway)}))

// no leeway: valid up to the exact time; expired if issued one ns in the future
assert.NoError(t, c.ValidateWithLeeway(Expected{Time: now}, 0))
err = c.ValidateWithLeeway(Expected{Time: now.Add(-1)}, 0)
if assert.Error(t, err) {
assert.Equal(t, err, ErrIssuedInTheFuture)
}
}

0 comments on commit 018cad1

Please sign in to comment.