jwt icon indicating copy to clipboard operation
jwt copied to clipboard

Add option to change time precision for creation/parsing tokens.

Open ajermaky opened this issue 1 year ago • 5 comments

We can currently change the precision of timestamps getting serialized by modifying TimePrecision here. However we are running into an issue where we have to serialize/validate different jwt tokens of various precisions (i.e. seconds, milliseconds).

As a work around, we are creating our own version of jwt.RegisteredClaims that serializes/deserializes times based on the precision that we want. However it would be nice if we can include a time precision option in jwt.New or jwt.ParseWithClaims

ajermaky avatar Jul 23 '24 18:07 ajermaky

I had a similar feature in mind a while ago. This was previously not possible, but recently we changed the way the parser/validator works and both can now be supplied with options that are accessible in the respective (de)serialisation functions, so this might work.

You could probably take some hints from https://github.com/golang-jwt/jwt/pull/301. Specifically you need to apply the token options to the created token like this (which is not yet in main): https://github.com/golang-jwt/jwt/pull/301/files#diff-2feccbe0109db2f6b93af0c4afed26af571a61438266ebd8690bf669c75d2874R63-R66

Just to add, I am not quite sure why, but after writing these lines I think there was still some kind of issue with this we could not work around... But I cannot remember, so feel free to try it ;)

oxisto avatar Jul 23 '24 19:07 oxisto

makes sense! Will take a crack and give and update!

ajermaky avatar Jul 27 '24 02:07 ajermaky

Hmm I remember now why this probably won’t work. You will not have access to the options in the unmarshal func of NumericDate. I would be interested in how you solved this problem in your workaround.

oxisto avatar Jul 27 '24 11:07 oxisto

You will not have access to the options in the unmarshal func of NumericDate.

Can Confirm, this is the issue i'm hitting against!

I am mainly working with the idea to add a precision field to NumericDate and remove any calls to truncate the time until it gets fetched, i.e.

type NumericDate struct {
	t time.Time
	precision time.Duration
}

func (d *NumericDate) Time() time.Time{
    return d.t.Truncate(d.precision)

}

But like you said, parser won't be able to control the unmarshal issue. The one idea I had was to update the claims interface as:

type Claims interface {
	GetExpirationTime() (*NumericDate, error)
	GetIssuedAt() (*NumericDate, error)
	GetNotBefore() (*NumericDate, error)
	GetIssuer() (string, error)
	GetSubject() (string, error)
	GetAudience() (ClaimStrings, error)
	SetPrecision(time.Duration)
}

And registered claims being something like:


func (c RegisteredClaims) SetPrecision(precision time.Duration) {
	c.ExpiresAt.precision = precision
	c.NotBefore.precision = precision
	c.IssuedAt.precision = precision
}

And inside the parser, we call it before getting unmarshalled i.e.

token.Claims = claims
prec = // if options nil, use default time.Second
token.Claims.SetPrecision(prec)
...
err = json.Unmarshal(claimBytes, &claims)

That looks like it may work, but it feels a bit wonky. I think specifically main issues:

  • This works very well for RegisteredClaims - not so much for MapClaims. There is maybe a hack where we store an additional precision field in the map, but I think that's dangerous to do.
  • Adds additional complexity for users implementing their own claims
  • Would require us to lose embedding of time object in NumericDate (although I can see a usecase where we set precision and truncate in place)
  • This would only help with NumericDate that are part of Claims interface - if we define any other NumericDate in a custom claims, there isn't really a way for us to systematically update it.

I do think adding a precision field on the NumericDate object would be a step in the right direction, as that would give us more control, but not seeing a way for the parser to control that.

Curious on your thoughts!

ajermaky avatar Jul 27 '24 18:07 ajermaky

we are probably stuck here until the v2 version of json arrives with options. See https://pkg.go.dev/github.com/go-json-experiment/json#Options

oxisto avatar Aug 29 '24 08:08 oxisto