feat(jwksauth)!: align with upstream JWT_PRIVATE_CLAIM_PREFIX#27
Conversation
- Decode server-attested Domain/Project/ServiceAccount under a configurable prefix (default "extra"); add WithPrivateClaimPrefix option with format validation
- Surface remaining caller-supplied payload keys via Claims.Extras and TokenInfo.Extra(key)
- Remove the special-cased Tenant field and Tenant() helper; tenant is now a caller-supplied key under Extras
- Precompute prefixed payload keys at construction to keep the verify hot path allocation-free
- Migrate existing tests from bare to prefixed claim keys; add new e2e tests covering prefix configuration
BREAKING CHANGE: Server-attested claims are now read from "<prefix>_domain",
"<prefix>_project", "<prefix>_service_account" (default prefix "extra")
rather than bare keys; pair this SDK release with an AuthGate Server that
includes upstream PR #182. Claims.Tenant and TokenInfo.Tenant() are
removed — read tenant via TokenInfo.Extra("tenant"), e.g.
v, _ := info.Extra("tenant"); s, _ := v.(string).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Aligns jwksauth JWT-claim decoding with AuthGate’s upstream JWT_PRIVATE_CLAIM_PREFIX rollout by moving server-attested private claims to a configurable <prefix>_<logical> naming scheme (default extra_*), and replacing the prior special-cased tenant handling with a generic Claims.Extras surface.
Changes:
- Add
WithPrivateClaimPrefix+ prefix validation at verifier construction; precompute resolved claim keys for the verify hot path. - Replace
Claims.Tenant/TokenInfo.Tenant()withClaims.Extras+TokenInfo.Extra(key)and update middleware/access-rule behavior accordingly. - Add/update unit + integration-style tests and refresh package docs/README for the new claim/prefix contract.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| jwksauth/options.go | Introduces default prefix (extra), validation rules, and WithPrivateClaimPrefix. |
| jwksauth/verifier.go | Validates prefix at construction and passes precomputed claim keys into decoding. |
| jwksauth/multi_verifier.go | Same prefix validation/key precompute for multi-issuer verification; updates cross-domain doc text. |
| jwksauth/claims.go | Reworks claim decoding to read prefixed server-attested keys and collect remaining non-standard keys into Claims.Extras; adds TokenInfo.Extra. |
| jwksauth/access_rule.go | Updates rule docs to clarify only server-attested claims participate; Extras are app-enforced. |
| jwksauth/access_rule_test.go | Updates tests to reflect Extras behavior (no tenant field filtering). |
| jwksauth/middleware_test.go | Migrates tests to extra_* claims and replaces tenant assertions with Extra("tenant"). |
| jwksauth/claims_prefix_test.go | Adds new tests covering default/custom prefixes, bare-claim behavior, and prefix validation. |
| jwksauth/doc.go | Updates package-level docs to explain the private-claim prefix and Extras. |
| jwksauth/README.md | Updates user-facing docs/examples for prefixed claims and Extras usage. |
| CLAUDE.md | Notes the default private-claim prefix and the WithPrivateClaimPrefix override. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Use guarded type assertions on TokenInfo.Extra results so non-string values produce a clean test failure instead of panicking - Reword the README to acknowledge that server-attested private claims are optional, not always emitted - Document on Claims that the struct is populated by the SDK verifier and is not intended for direct JSON marshal/unmarshal Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Reword the staticReservedClaimKeys comment to describe what the set actually represents (a hand-picked exclusion list mixing JWT, OIDC, and AuthGate-specific keys), not the full OIDC standard registry - Update the README's caller-supplied-keys paragraph to note that OIDC claims the SDK does not name explicitly (email, name, etc.) will land in Extras when the issuer emits them Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Apply strings.TrimSpace inside WithPrivateClaimPrefix so values sourced from environment variables or config files don't trip prefix validation on incidental leading/trailing whitespace - Treat whitespace-only input the same as empty (use the default prefix), consistent with the existing zero-input convention - Add a focused test pinning both the trimmed-prefix decode path and the whitespace-only fallback to default Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Reword the Claims godoc to be precise about Go's default JSON marshal behavior on a tag-less struct (exported fields are emitted under their Go names like ClientID, not the snake_case JWT keys), instead of suggesting JSON marshal is somehow blocked - Drop the duplicated "With" in the TestPrefixedClaims_CustomPrefix doc comment Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Extras' field comment claimed it carried "any payload keys that are neither JWT/OIDC standard claims" — but the SDK only filters a hand-picked reserved set, so common OIDC claims like email and name still surface via Extras. Reword the comment to reference the actual reserved set, and update TestMiddleware_DomainPresent_NoExtras's docstring to acknowledge that newTokenInfo leaves Claims.Extras nil (rather than allocating an empty map) when no caller-supplied keys exist; assert that nil contract explicitly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…y-input semantics
Two doc fixes flagged by review on the option godoc:
1. Multi-issuer caveat. MultiVerifier caches a single resolved
claimKeys set, so passing issuers with different
JWT_PRIVATE_CLAIM_PREFIX values to one MultiVerifier silently
misreads claims for the mismatched issuer(s). Document that one
MultiVerifier serves a single prefix; users with mixed prefixes
should build one Verifier per prefix.
2. Empty-input behavior. The previous wording ("treated as use the
default") suggested WithPrivateClaimPrefix("") would revert an
earlier non-default call, but the implementation simply skips the
assignment when trimmed input is empty. Reword to "no-op: leaves
the previously-configured prefix in place" so the doc and code
agree.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [github.com/go-authgate/sdk-go](https://github.com/go-authgate/sdk-go) | `v0.9.0` → `v0.10.0` |  |  | --- ### Release Notes <details> <summary>go-authgate/sdk-go (github.com/go-authgate/sdk-go)</summary> ### [`v0.10.0`](https://github.com/go-authgate/sdk-go/releases/tag/v0.10.0) [Compare Source](go-authgate/sdk-go@v0.9.0...v0.10.0) #### Changelog ##### Others - [`5b43693`](go-authgate/sdk-go@5b43693): feat(jwksauth)!: align with upstream JWT\_PRIVATE\_CLAIM\_PREFIX ([#​27](go-authgate/sdk-go#27)) ([@​appleboy](https://github.com/appleboy)) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNjAuNiIsInVwZGF0ZWRJblZlciI6IjQzLjE2MC42IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119--> Reviewed-on: https://gitea.com/gitea/tea/pulls/976 Co-authored-by: Renovate Bot <renovate-bot@gitea.com> Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
Summary
Aligns
jwksauthwith upstream AuthGate PR#182, which moved
server-attested private claims from bare names (
domain/project/service_account) to a configurable<prefix>_<logical>scheme (defaultextra_*). AddsWithPrivateClaimPrefix, replaces the previouslyspecial-cased
Tenantfield/helper with a genericClaims.Extrasmap,and surfaces individual values via
TokenInfo.Extra(key).This is a hard cutover; pair this SDK release with an AuthGate Server
that includes upstream PR #182.
AI Authorship
pass on
jwksauth/claims.go,jwksauth/options.go,jwksauth/verifier.go, andjwksauth/multi_verifier.gofrom asecond reviewer before merge
Change classification
(
Claims.Tenant,TokenInfo.Tenant()); on-the-wire contract changePlan reference
See
plan.md(worktree-local). Goal: align SDK consumers with theupstream
JWT_PRIVATE_CLAIM_PREFIXrollout so default-prefix tokenscontinue to decode correctly, custom-prefix deployments have a knob, and
tenantis treated as a caller-supplied dimension (not a server-attestedfield).
Verification
validatePrivateClaimPrefixtable-driven positives & negativesclaims_prefix_test.goexercises real go-oidcverification against an in-process JWKS issuer
- Happy path (default prefix, all three server-attested claims hit)
- Custom prefix (
acme_*hits;extra_*against anacme-configuredverifier yields empty Domain → fail-closed)
- Bare claim ignored (token with bare
domainrejected by AccessRule;bare key surfaces via Extras)
- Caller-supplied keys (
extra_foo&fooboth land in Extras, neitherpromotes into typed Claims)
- Invalid prefix rejected at construction (
NewVerifierandNewMultiVerifier)client_credentials, feed the issued token through the README snippet,
confirm
info.Claims.Domain / Project / ServiceAccountare populated andinfo.Extra("tenant")returns the caller-supplied value (if any).Verifiability check
Claims/TokenInfo/WithPrivateClaimPrefixgodoc andjwksauth/README.mdpath is one function (
newTokenInfo) and easy to readslog-based policylog (
jwksauth: policy reject); AccessRule fails closed on missingvalues
Security check
validateJWTPrivateClaimPrefix)bare-key and wrong-prefix cases)
MultiVerifier.Verifyerror shape unchangedRisk & rollback
SDK reads them as empty, AccessRule blocks legitimate tokens.
Mitigation: synchronize releases; the BREAKING flag in the commit
signals this.
WithPrivateClaimPrefix→ same fail-closed symptom. Mitigation: README and godoc emphasize
byte-for-byte agreement; test 2 pins the expected behavior.
Claims.Tenant/TokenInfo.Tenant()break at compile time. Mitigation: 1:1 replacement via
v, _ := info.Extra("tenant"); s, _ := v.(string); commit message andgodoc surface this.
jwksauth/CLAUDE.mdare touched. Consumers whoshipped against this SDK version with PR #182 servers will need to
revert both ends.
Reviewer guide
jwksauth/claims.go— the newnewTokenInfodecode path: confirm thereserved-keys list matches upstream's
staticReservedClaimKeys,confirm Extras population by reference is intentional, confirm
type-assert-fail-as-empty is acceptable for non-string values
jwksauth/options.go—WithPrivateClaimPrefixempty-string-as-defaultsemantics and
validatePrivateClaimPrefixrules vs. upstreamjwksauth/verifier.go&multi_verifier.go— prefix validationplacement and the new
claimKeysprecomputationaccess_rule.go(godoc-only),doc.go(godoc-only).🤖 Generated with Claude Code