0

I need to extract the expiry date of firebase tokens. How can I extract the "exp" from the token in java?

I tried to use code from https://connect2id.com/products/nimbus-jose-jwt/examples/validating-jwt-access-tokens using com.nimbusds:nimbus-jose-jwt:9.23 but it fails:

    String accessToken = "...";

    // Create a JWT processor for the access tokens
    ConfigurableJWTProcessor<SecurityContext> jwtProcessor =
            new DefaultJWTProcessor<>();

    // Set the required "typ" header "at+jwt" for access tokens issued by the
    // Connect2id server, may not be set by other servers
    jwtProcessor.setJWSTypeVerifier(
            new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("at+jwt")));

    // The public RSA keys to validate the signatures will be sourced from the
    // OAuth 2.0 server's JWK set, published at a well-known URL. The RemoteJWKSet
    // object caches the retrieved keys to speed up subsequent look-ups and can
    // also handle key-rollover

    // I changed it to what I think should work for firebase, but it doesn't seem to matter what I put here:

    JWKSource<SecurityContext> keySource =
            new RemoteJWKSet<>(new URL("https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken@system.gserviceaccount.com"));

    // The expected JWS algorithm of the access tokens (agreed out-of-band)
    JWSAlgorithm expectedJWSAlg = JWSAlgorithm.RS256;

    // Configure the JWT processor with a key selector to feed matching public
    // RSA keys sourced from the JWK set URL
    JWSKeySelector<SecurityContext> keySelector =
            new JWSVerificationKeySelector<>(expectedJWSAlg, keySource);

    jwtProcessor.setJWSKeySelector(keySelector);

    // Set the required JWT claims for access tokens issued by the Connect2id
    // server, may differ with other servers
    jwtProcessor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier(
            null,
            new HashSet<>(Arrays.asList("exp"))));

    // Process the token
    SecurityContext ctx = null; // optional context parameter, not required here
    JWTClaimsSet claimsSet = jwtProcessor.process(accessToken, ctx);

    // Print out the token claims set
    System.out.println(claimsSet.toJSONObject());

I get this error:

JOSE header "typ" (type) "JWT" not allowed
com.nimbusds.jose.proc.BadJOSEException: JOSE header "typ" (type) "JWT" not allowed
    at com.nimbusds.jose.proc.DefaultJOSEObjectTypeVerifier.verify(DefaultJOSEObjectTypeVerifier.java:149)
    at com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:341)
    at com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:303)
    at com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:294)
Gavriel
  • 18,880
  • 12
  • 68
  • 105
  • See the comment on the second code line: *Set the required "typ" header "at+jwt" for access tokens issued by the Connect2id server* - you're setting the required header to "at+jwt", the actual token has only "jwt", so it does not meet the requirement. Try setting it to "jwt". – jps Jun 08 '22 at 11:45
  • Well that's 1 step forward :) but unfortunately my guess about the keySource was wrong: Couldn't parse remote JWK set: Missing required "keys" member – Gavriel Jun 08 '22 at 19:46
  • Does [this](https://stackoverflow.com/questions/55594930/getting-jwks-for-firebase-in-rfc7517-format) help for the second step? – jps Jun 08 '22 at 20:13
  • Sort of. Using "https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com" gives me another error, so I guess it's one more step: Expired JWT. However maybe the whole thing I do (with the copy&pasted code) is an overkill? I don't want any validation, the only thing I am interested in is the "exp" from the token. I don't care if it's fake, because it's already checked by firebase, I need the exp to be able to differentiate between the annoyingly "coupled" error messages: "Firebase ID token has expired or is not yet valid. Get a fresh ID token and try again" – Gavriel Jun 09 '22 at 00:09
  • 2
    if you just need to read the "exp" claim, it's indeed overkill. A JWT consists of two Base64Url encoded JSON objects and a signature, all connected with dots. The easiest is to Base64Url decode the second part of the token (the payload), parse the JSON object, and read the "exp" (Unix epoch time). Search for "java jwt decode". – jps Jun 09 '22 at 06:30
  • @jps YES! Thank you! If you add it as an answer I'll accept. – Gavriel Jun 09 '22 at 10:19

0 Answers0