kylef / JSONWebToken.swift

Swift implementation of JSON Web Token (JWT).
http://jwt.io
BSD 2-Clause "Simplified" License
762 stars 226 forks source link

Issued at claim (iat) is in the future #54

Closed realmike33 closed 7 years ago

realmike33 commented 7 years ago

Got this error when trying to decode JWT. As per the python implementation, this shouldn't be a thing.

Should update.

realmike33 commented 7 years ago

opened pull request

JanBrinker commented 7 years ago

I'm having the same issue from time to time. As far as I see this happens due to rounding of the timestamps. For example this morning I sent a request and got a token in response that had an iat of 1504765492. Just before validating the token I printed out my current timestamp and it was 1504765491.78288. As the token expects an integer in the iat field and iOS's Date() uses Double to model sub second accuracy, we might have a current Date() that is before iat.

However I don't agree with your pull request to completely remove this error from the code base.

This could be solved by always rounding the current date down before comparing to the iat claim. Do you agree @kylef?

kylef commented 7 years ago

This could be solved by always rounding the current date down before comparing to the iat claim.

@JanBrinker I think the better solution would to be support some form of leeway, some value of time that can be passed to the library to allow extra time.

Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew. Its value MUST be a number containing a NumericDate value. Use of this claim is OPTIONAL.

JanBrinker commented 7 years ago

@kylef that could work aswell and could also be implemented more nicely by just using Date().addingTimeInterval(...) for comparison instead of Date().

In that case the question would be how to pass the leeway into the library or whether it should be a constant. What do you think?

kylef commented 7 years ago

@JanBrinker I think I'd do the following:

JanBrinker commented 7 years ago

@kylef shall we introduce several different leeways for the different claims? So one for nbf, one for exp and one for iat? Even if a leeway for iat is not defined in the specs?

kylef commented 7 years ago

@JanBrinker I think it would be rare that a user would want that granularity, that they would want to specify different values (but I could be wrong).

The design would allow them to do this by manually calling the validations for this unusual case. Do you think there would be a warrant for use-case to provide separate values in the code and validate functions?

let claimset = decode(..., validate: false)
claimset.validateIssuer("x")
claimset.validateIssuedAt(leeway: 5)
claimset.validateExpiary(leeway: 5)

I would lean towards a single value to keep the API simpler for the 99%, but willing to consider it if you think there are use-cases. Looking at the other libraries it seems they are split:

From PyJWT, they support a single value:

jwt.decode(jwt_payload, 'secret', leeway=10, algorithms=['HS256'])

From ruby-jwt, they support separate leeways:

decoded_token = JWT.decode token, hmac_secret, true, { :exp_leeway => leeway, :algorithm => 'HS256' }
JanBrinker commented 7 years ago

I was just thinking about the two different cases that we have with exp (leeway is subtracted from Date()) vs. iat and nbf (leeway is added to Date()). But you're right. Let's go for one parameter. The purpose is to account for skewed clocks. Clock skew does not change that fast to matter differently for different checks.. or if it does you have different problems anyway.

I'm on it now. Will also write unit tests and create a pull request for you :)

kylef commented 7 years ago

@JanBrinker Awesome, let me know if you need any help.

kylef commented 7 years ago

Closed by #83.