Skip to content

Do not reject present aud claim when audience is None#409

Open
arpitjain099 wants to merge 1 commit into
mpdavis:masterfrom
arpitjain099:fix/aud-none-no-validation
Open

Do not reject present aud claim when audience is None#409
arpitjain099 wants to merge 1 commit into
mpdavis:masterfrom
arpitjain099:fix/aud-none-no-validation

Conversation

@arpitjain099
Copy link
Copy Markdown

Fixes #389

Problem

jwt.decode(..., audience=None) is the documented way to decode a token without verifying its audience, but it raises JWTClaimsError("Invalid audience") whenever the token happens to carry an aud claim.

The cause is the final membership check in _validate_aud (jose/jwt.py):

if audience not in audience_claims:
    raise JWTClaimsError("Invalid audience")

When the caller passes audience=None, None is never a member of audience_claims, so any token that contains an aud claim fails verification even though the caller asked for no audience check.

Why this is the correct behavior

RFC 7519 section 4.1.3 ties audience verification to a principal identifying itself:

Each principal intended to process the JWT MUST identify itself with a value in the audience claim. If the principal processing the claim does not identify itself with a value in the "aud" claim when this claim is present, then the JWT MUST be rejected.

A caller that passes no audience (audience=None) is not identifying itself as an intended recipient, so a present aud claim should not on its own cause rejection. PyJWT behaves the same way: it only enforces the aud claim when an audience is supplied.

Fix

Guard the membership check so it only runs when an audience was actually provided:

if audience is not None and audience not in audience_claims:
    raise JWTClaimsError("Invalid audience")

Behavior preserved:

  • audience=None (or omitted) with an aud claim present: no longer raises.
  • A supplied audience that matches: passes, as before.
  • A supplied audience that does not match: still raises JWTClaimsError.
  • verify_aud=False: unaffected (the whole check is already skipped upstream).

Tests

Added four tests to tests/test_jwt.py:

  • test_aud_none_with_aud_claim_present
  • test_aud_none_with_aud_list_claim_present
  • test_aud_none_default_argument
  • test_aud_verify_disabled_with_aud_claim

The three audience=None tests fail against the current code and pass with the fix. The full tests/test_jwt.py suite passes (65 tests), and black/isort are clean on the changed files.

jwt.decode(..., audience=None) is the documented way to skip audience
verification, but _validate_aud still ran the final membership check and
raised JWTClaimsError("Invalid audience") whenever the token carried an
aud claim. RFC 7519 4.1.3 only requires the aud claim to be checked when
a principal identifies itself as an intended recipient; a caller that
passes no audience is not identifying itself, so a present aud claim must
not cause failure. This also matches PyJWT, which skips the check when no
audience is supplied.

Guard the membership check with audience is not None. A supplied audience
still has to match (mismatch raises as before), and verify_aud=False is
unaffected.

Fixes mpdavis#389

Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
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

Successfully merging this pull request may close these issues.

JWT aud validation raises "Invalid audience" for audience=None

1 participant