Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add jwt as a property of JwtExceptions #148

Closed
edjiang opened this issue Jul 14, 2016 · 10 comments
Closed

Add jwt as a property of JwtExceptions #148

edjiang opened this issue Jul 14, 2016 · 10 comments

Comments

@edjiang
Copy link

edjiang commented Jul 14, 2016

When you try to parse the claims of a JWT, even when it fails validation, there may be instances where you would want to still read the claims.

Talking with @lhazlewood today, we came up with the following idea: adding the parsed JWT as a property of JwtException, so you could so something like:

try {

    Jwts.parser().setSigningKey(key).parseClaimsJws(compactJws);

    //OK, we can trust this JWT

} catch (ExpiredJwtException e) {

    //don't trust the JWT!
    String subject = e.jwt.getBody().getSubject();
    System.out.println("Error: " + subject + "'s jwt failed valiation")
}

This would solve the #86 use case.

@mooseburgr
Copy link

Is this still desired? Looking to contribute and this feature seems like a decent way to get my feet wet in here.

@lhazlewood
Copy link
Contributor

lhazlewood commented Aug 14, 2020

Hi @mooseburgr - thanks for checking in! It is potentially - but there are a lot of changes happening right now in the JWE branch as that is our highest priority. Also a new validation framework may obviate the need for this particular approach - still working on that. So I'd ask to hold off on this in the meantime while we work on those two things - I wouldn't want to introduce more changes/change conflicts as the burden currently is pretty high. My hope is to have this stuff wrapped up in a few weeks as this is my highest coding priority at the moment.

@mooseburgr
Copy link

Sure, makes sense. It definitely looks like a lot going on there! Outsider looking in, but let me know if there's any grunt work I could help with.
Thanks for the quick reply, and for all of your hard work! 🙇

@runnermann
Copy link

Hello, We are running into the same issue while attempting to parse claims from an expired token. We need a way to ignore that a token has expired, and allow other exceptions to be thrown. This assists to ensure that a token is from the correct originator, and allows us to use it, along with other validation information, to refresh for that user. Thanks for all of the hard work on this.

@hertg
Copy link

hertg commented Sep 28, 2022

I just realized that I may have left my comment in the wrong issue. I am currently implementing the OpenID Connect RP-Initiated Logout 1.0 specification for an OpenID Connect Provider and have exactly the same requirement as @runnermann while parsing the id_token_hint parameter. From the spec:

[...] The OP SHOULD accept ID Tokens when the RP identified by the ID Token's aud claim and/or sid claim has a current session or had a recent session at the OP, even when the exp time has passed.

@bdemers
Copy link
Member

bdemers commented Sep 28, 2022

One way you could do this is to catch an ExpiredJwtException, then parse the token again with a custom Clock, that returns some date in the future (days, years, etc):

JwtParser jwtParser = Jwts.parserBuilder()
    .setSigningKey(...)
    .setClock( () -> Instance.now().plus(<days>).toDate())
    .requireIssuer("https://issuer.example.com")
    .build();

// ...
jwtParser.parse(jwtString)

NOTE: example above is half memory / half copypasta.

The downside is you parse the token twice.

And trusting the data in an expired token does come with risk.

@hertg
Copy link

hertg commented Sep 28, 2022

@bdemers Hmmm, interesting workaround 🤔
Wouldn't I need to set the clock into the past for expired tokens to get accepted? I could certainly do that, just in the specific method where I don't care about the exp of course. I'm guessing I can't just set that to 1970-01-01 to accept any exp values because the clock probably also influences the nbf check right? That's why you proposed the "double parse" method?

I could also manually base64url decode the body, read the iat and set the clock to the extracted iat, and then parse the whole thing through jjwt with the adjusted clock. As I'm already in the realm of hacky workarounds, that probably still is the better solution than trying to implement the parsing/signature check myself just for that one method.

@bdemers
Copy link
Member

bdemers commented Sep 28, 2022

@hertg you are spot on, my suggestion would not work because of the nbf claim.
Sorry about that!

@hertg
Copy link

hertg commented Sep 29, 2022

@bdemers thanks for the idea, I think I'll go ahead with something like that.

final String body = jwtString.split("\\.")[1];
final String jsonString = new String(Base64.getUrlDecoder().decode(body), StandardCharsets.UTF_8);
final JsonNode json = Json.parse(jsonString);
final long seconds = json.get("iat").asLong();
JwtParser parser = Jwts.parserBuilder()
    .requireIssuer(...)
    .setSigningKeyResolver(...)
    .setClock(new FixedClock(Date.from(Instant.ofEpochSecond(seconds))))
    .build();

Warning: For anyone that wants to use that code, be aware that the iat claim is an OPTIONAL field per RFC7519. In my case I can rely on the iat being there because the ID Token I'm parsing has marked the iat claim as REQUIRED.
Also, this doesn't work with encrypted tokens for obvious reasons :)

@lhazlewood lhazlewood removed this from the 0.12.0 milestone Aug 11, 2023
@lhazlewood
Copy link
Contributor

With the merge of the #113 that allows for custom SignatureAlgorithm instances (where a custom implementation can just not compute a signature so they can see a resulting payload), as well as with the work for #474 (to use custom validators that may ignore or lessen restrictions on exp or nbf claims), this issue is no longer necessary/relevant. Closing in in favor of #474 for tracking relevant work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants