Skip to content

fix: populate aud claim on every issued token (JWT-SVID section3)#85

Merged
rsharath merged 4 commits intomainfrom
issue42
Apr 23, 2026
Merged

fix: populate aud claim on every issued token (JWT-SVID section3)#85
rsharath merged 4 commits intomainfrom
issue42

Conversation

@rsharath
Copy link
Copy Markdown
Contributor

Problem

Tokens issued without an explicit audience had no aud claim at all. internal/service/credential.go
only set the claim inside if len(req.Audience) > 0. This:

  • Violates JWT-SVID Section3 (which requires aud on every issued token)
  • Violates RFC 7519 Section4.1.3 guidance
  • Breaks interop with spec-compliant verifiers — including ZeroID's own pkg/authjwt client when
    configured with an expected audience

Fix

Default aud to the issuer URL when the caller does not supply one. Every grant routes through CredentialService.IssueCredential, so a single change covers all paths (client_credentials, jwt_bearer, token_exchange, api_key, authorization_code, refresh_token).

aud := req.Audience
if len(aud) == 0 {
    aud = []string{s.issuer}
}                                                                                                         
_ = token.Set(jwt.AudienceKey, aud)

Explicit audiences (set via the admin /credentials/issue endpoint) are preserved; the default only fills the empty case.

Tests

New file tests/integration/jwt_svid_aud_test.go:

  • TestIssuedTokenHasAudClaimDefault: client_credentials with no audience → aud = [issuer]
  • TestIssuedTokenPreservesExplicitAudience: admin /credentials/issue with explicit audience → preserved, not clobbered
  • TestAuthjwtAcceptsDefaultedAudience: end-to-end proof that a defaulted token verifies under an authjwt.Verifier configured with Audience: issuer (positive path), and that the verifier correctly rejects a mismatched audience with ErrInvalidAudience (negative null-test)

Test plan

  • go build ./... clean
  • go vet ./... clean
  • gofmt -l clean for modified files
  • Full integration suite passes
  • Three new tests pass
  • golangci-lint (ci-lint PR config) clean for modified files

@rsharath rsharath requested review from KunalJavelin and saucam April 21, 2026 05:05
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request ensures that issued JWTs always contain an "aud" claim by defaulting to the issuer URL when no audience is specified, satisfying JWT-SVID §3 requirements. Integration tests have been added to verify both the default behavior and the preservation of explicit audiences. A review comment identifies a potential issue where the "RotateCredential" method may now incorrectly default the audience for rotated tokens instead of preserving the original audience, which could impact client interoperability.

Comment thread internal/service/credential.go
@rsharath rsharath merged commit 6f84983 into main Apr 23, 2026
9 checks passed
@rsharath rsharath deleted the issue42 branch April 23, 2026 06:28
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.

2 participants