feat: opt-in claim validation (--verify-claims, --aud, --iss) - #21
Merged
Conversation
Add explicit, opt-in RFC 7519 claim validation that can fail the exit code, without changing the default behavior. --verify-claims enforces the temporal claims (exp, nbf); --aud and --iss additionally require a specific audience or issuer and imply validation. The result prints as a Claims: VALID / INVALID section and is reported as claimsValid under --json. Validation is deliberately independent of signature verification: it runs with or without --key, shares the display clock (jwt.WithTimeFunc(timeNow)) so verdicts agree with the expired / not-yet-valid annotations, and uses go-jwt's validator rather than reimplementing the checks. When both a key and claim flags are given, both sections are shown and the command exits nonzero if either fails, with the signature verdict taking precedence for the returned sentinel. A missing exp is not treated as expired, and claim flags on a JWE emit a note and are skipped. The pre-existing invariant is preserved: a bare decode never fails on expiry — nothing validates claims unless a claim flag is passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
bsg62
added a commit
that referenced
this pull request
Jul 25, 2026
Add a "Validate claims" capability card covering --verify-claims and the --aud/--iss assertions, placed after "Verify signatures" and renumbering the following cards. Reflects the opt-in claim validation shipped in #21.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements #1 from the improvement list: optional, explicit claim validation that can affect the exit code — without changing the default decode-only behavior.
Behavior
--verify-claimsvalidates the temporal claims (exp,nbf) and exits nonzero if the token is expired or not yet valid.--aud <value>/--iss <value>additionally require a specific audience/issuer and imply validation (so they work without also passing--verify-claims).Claims: VALID/Claims: INVALIDsection with the reason, and asclaimsValidunder--json.Design decisions
--key. When both are used, both sections are shown and the command exits nonzero if either fails (signature verdict takes precedence for the returned sentinel). This preserves the existing invariant that a bare decode never fails on expiry — nothing validates claims unless a claim flag is passed.go-jwt'sjwt.NewValidatorwithjwt.WithTimeFunc(timeNow), so verdicts agree with the existingexpired/not yet validdisplay annotations and are deterministic under thepinTimetest helper. Reusing the library's validator avoids reimplementing crypto-adjacent checks.expis not expired (standard JWT semantics); no leeway (matches the exact-time annotations).decodeAndPrintis untouched; the human path runs claim validation as a separate section via a newdecodeJWTHuman, and onlydecodeJWTJSONgained theclaimChecksparameter.Tests
New
claims_test.gocoversvalidateClaimsSet(live/expired/not-yet-valid, aud/iss match·mismatch·missing, joined multi-failures, missing-exp-is-valid),verifyClaims(VALID/INVALID output, sentinel, hard error on unparseable token),claimReasonflattening, and integration throughdecodeJWTHuman/decodeJWTJSON(section ordering, both-checks precedence,claimsValidomitted when not requested). Full suite +go vet+gofmtclean.Follow-up (not in this PR)
The marketing site's capabilities list still says signatures are checked "independently from claim validation"; adding a claim-validation capability entry there is a separate docs change I've left out to keep this PR focused.
🤖 Generated with Claude Code