AudValidator::validate() doesn't adhere to requireAudience boolean if jwtClaims audience present

Issue #120 invalid
Anthony S created an issue

If jwtClaims contains an audience, then AudValidator::validate() should check if the requireAudience boolean is set to false before checking the audience value. For instance, I specify requireAudience to false in the setExpectedAudience() setter if audience is null or zero length when constructing a JwtConsumer as below:

    JwtConsumer jwtConsumer = new JwtConsumerBuilder()
        .setRequireExpirationTime() // the JWT must have an expiration time
        .setAllowedClockSkewInSeconds(allowedClockSkewInSeconds)
        .setExpectedIssuer(((iss != null) && (iss.length() > 0)) ? true
            : false,
            ((iss != null) && (iss.length() > 0)) ? iss
                : null) // whom the JWT needs to have been issued by
        .setExpectedAudience(((aud != null) && (aud.length() > 0)) ? true
            : false,
            ((aud != null) && (aud.length() > 0)) ? aud
            : null) // to whom the JWT is intended for
        .setVerificationKeyResolver(httpsJwksKeyResolver)
        .build();

I see that the IssValidator follows the same pattern. It doesn't check requireIssuer if an issuer is present in the jwtClaims, but requireIssuer is false.

Comments (6)

  1. Brian Campbell repo owner

    I'm not sure I follow exactly what your expectations are but I believe the audience checking is working as designed. See the javadoc for setExpectedAudience(...) here, which indicates that (unless explicitly disabled) the audience claim, If present, is always validated against the provided expected audience value(s). The requireAudienceClaim boolean only says whether or not the presence of the audience claim is required to pass validation. But regardless of requireAudienceClaim, if an aud claim is in the token, it is checked against the expected audience value(s).

  2. Anthony S reporter

    Many thanks for the reply Brian. I was trying to minimize the amount of code I have to write to handle multiple cases (i.e., issuer and/or audience specified or not). For instance, in my application above, there is the possibility that issuer and/or expected audience are not configured earlier in the application that consumes the JWT. I could get away with a single JwtConsumer instantiation above for all possible cases if I'm able to specify if the issuer or audience should be validated or not.

    However, I missed the reference to Section 4.1.3 of RFC 7519. To confirm I'm understanding it correctly, if an application that consumes a JWT states that issuer and/or audience should not be validated when instantiating the JwtConsumer, but the JWT does indeed contain those values, then validation should fail in any case?

    If so, then feel free to close this issue as a non-defect.

  3. Brian Campbell repo owner

    RFC 7519 basically says that a consumer of a JWT has to evaluate the aud claim if there is one in the token. The JwtConsumer[Builder] and API around setExpectedAudience(...) try to accommodate that. The requireAudienceClaim boolean is only a way to tell the JwtConsumer that some aud claim has to be in the token.

    If you really want/need to not validate audience at all, then you can use setSkipDefaultAudienceValidation() on the builder. But doing so does take things out of strict spec compliance and is less than ideal from a security perspective.

  4. Log in to comment