frasertweedale / hs-jose

Haskell JOSE and JWT library
http://hackage.haskell.org/package/jose
Apache License 2.0
122 stars 46 forks source link

Check JWT Expiration Time Without Verifying Token #126

Closed julmb closed 7 months ago

julmb commented 8 months ago

I am trying to use a web service provided by a third party. It has an authentication endpoint that expects HTTP Basic Authentication and upon successful authentication returns a JWT. This JWT can then be passed alongside requests to the other endpoints of the service in order to authorize access.

This JWT is valid for an hour and I would like to reuse it across multiple requests and only refresh/reacquire it once it has expired. In order to do this, I would like to read the expiration time of the JWT using jose. However, the documentation for verifyJWT says:

This is the only way to get at the claims of a JWS JWT, enforcing that the claims are cryptographically and semantically valid before the application can use them.

This sounds to me like in order to get the expiration time, I would have to fully verify the JWT. However, I cannot do so since I do not have the JWK. In this scenario, I am just passing the JWT from one endpoint to another, being neither the issuer of the token, nor the party interested in verifying it. So I think in this situation I am neither expected/required nor able to fully verify the JWT.

What should I do in this case?

frasertweedale commented 8 months ago

Thanks for reporting.

It is a security decision of hs-jose to prohibit any access to JWS payload except via verification. That said, you have described a legitimate use case for access to unverified payload data.

As of current releases, the best you can do is parse the token yourself and extract the raw payload byte, then decode using instance FromJSON ClaimsSet and access the expiration time field. So, hs-jose helps a little, but you still have some manual work.

I will contemplate adding an "unsafe get payload" capability to the library, to support this (and similar) use cases.

endgame commented 8 months ago

By the way, I don't think that it's possible in general to know whether the JWT has expired except by trying it. Even if you check the expiration time, your clock may not be in sync with the issuer's, your process might be suspended after the "is the JWT expired?" check and before the JWT is used, etc. PR #127 might let you make your program more efficient by not attempting requests which are likely to fail, but you'll still have to handle failures.