Open ajermaky opened 1 month ago
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 ;)
makes sense! Will take a crack and give and update!
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.
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:
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!
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
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 injwt.New
orjwt.ParseWithClaims