Skip to content

feat(token)!: namespace server-attested private claims under JWT_PRIVATE_CLAIM_PREFIX#182

Merged
appleboy merged 16 commits intomainfrom
feat/jwt-private-claim-prefix
May 2, 2026
Merged

feat(token)!: namespace server-attested private claims under JWT_PRIVATE_CLAIM_PREFIX#182
appleboy merged 16 commits intomainfrom
feat/jwt-private-claim-prefix

Conversation

@appleboy
Copy link
Copy Markdown
Member

@appleboy appleboy commented May 2, 2026

Summary

Introduces JWT_PRIVATE_CLAIM_PREFIX (default "extra") — a configurable namespace AuthGate prepends (with an _ separator AuthGate adds itself) to every server-attested private JWT claim. With the default, JWTs now carry extra_domain / extra_project / extra_service_account instead of bare domain / project / service_account. A deployment using JWT_PRIVATE_CLAIM_PREFIX=acme would emit acme_*. The bare logical names are gone — this is a hard cutover, called out below as a breaking change.

The new claim list lives in an unexported registry inside internal/token exposed via token.PrivateClaimRegistry() (returns a defensive copy). Future additions are a one-line append rather than scattered edits across emission, reserved-keys, and tests.

⚠️ BREAKING CHANGE

Server-attested private claims are no longer emitted under their bare names. Downstream services that read claims["domain"] / claims["project"] / claims["service_account"] directly must update at the same time as the AuthGate upgrade:

// before
domain := claims["domain"].(string)

// after (default prefix)
domain := claims["extra_domain"].(string)

// after (operator-chosen prefix, e.g. JWT_PRIVATE_CLAIM_PREFIX=acme)
domain := claims["acme_domain"].(string)

Token cache flush required. Tokens minted before the upgrade may sit in the cache with bare-name claims. Flush the token cache (Redis FLUSH or restart with empty memory cache) on upgrade, or wait for tokens to expire naturally. There is no automatic cache-key namespace bump.

AI Authorship

  • AI was used. Details:
    • Tool / model: Claude Opus 4.7 (1M context) via Claude Code, executing plan.md
    • AI-authored files: every file in this PR
    • Human line-by-line reviewed: TODO — author should mark which files they walked through line-by-line. Recommend prioritizing internal/config/config.go (validation), internal/token/reserved.go (reserved-set logic), internal/services/token.go (buildClientClaims / buildServerClaims / composeIssuanceClaims), and internal/services/token_extra_claims_parser.go.

Change classification

  • Core code (broad impact — needs line-by-line review)

This change alters the wire format of every issued JWT in every grant flow (authorization_code, device_code, client_credentials, refresh_token). Failure or regression spreads to every downstream consumer of AuthGate tokens. Reviewers should treat the issuance and reserved-key paths as security-critical.

Plan reference

Implementation followed plan.md on the branch. Goal: introduce a configurable prefix so downstream services can syntactically distinguish AuthGate-private claims from OIDC public claims, removing the per-deployment lookup table. Hard cutover by design.

Verification

  • Unit tests
  • Integration tests (services-level with sqlite store)
  • At least 3 e2e tests (1 happy path + 2 errors)
  • Stress / soak test: N/A — no new long-running paths
  • Manual verification suggested for reviewer:
    1. Boot with default config → issue any token → confirm JWT carries extra_domain / extra_project / extra_service_account (when configured) and bare names are absent.
    2. Set JWT_PRIVATE_CLAIM_PREFIX=acme, restart → issue token → confirm acme_* keys, extra_* and bare names absent.
    3. POST to /oauth/token with extra_claims={"extra_domain":"evil"} → expect 400 invalid_request.
    4. curl /.well-known/openid-configuration → confirm claims_supported does not list extra_domain (or any <prefix>_* private claim).
    5. Set invalid prefixes (extra_, 1bad, 16-char) → expect startup failure with a clear message.

Test coverage added in internal/services/token_private_claim_prefix_test.go:

Test Covers
TestPrivateClaimPrefix_DefaultPrefix_HappyPath client_credentials with default prefix; bare names absent
TestPrivateClaimPrefix_CustomPrefix acme prefix; extra_* and bare names absent
TestPrivateClaimPrefix_CallerCannotImpersonatePrefixedClaim Two-layer defense: parser rejection + service-layer override
TestPrivateClaimPrefix_CallerCannotInjectBareLegacyName Bare domain/project/service_account blocked at parser AND stripped at sign time
TestPrivateClaimPrefix_CallerCannotInjectDefaultPrefixOnCustomDeployment On prefix=acme, smuggled extra_* blocked at parser AND stripped at sign time
TestPrivateClaimPrefix_RefreshContinuity Refresh re-emits prefixed claims correctly
TestPrivateClaimPrefix_RegistryTableDriven EmittedName composes consistently for every entry returned by PrivateClaimRegistry()
TestJWTPrivateClaimPrefix_StartupValidation Empty / digit-prefix / hyphen / trailing-_ / oversized prefix
TestDetectPrefixCollision_Synthetic (config package) Collision-rejection branch via pure helper + synthetic logical name

Existing tests (token_domain_test.go, token_extra_claims_test.go, local_test.go, reserved_test.go, oidc_test.go) were updated to use the prefixed names from config rather than the deleted constants.

make generate && make fmt && make lint && make test are all green.

Verifiability check

  • Inputs and outputs documented (env var, JWT key shape) in .env.example, docs/CONFIGURATION.md, docs/JWT_VERIFICATION.md, CLAUDE.md
  • Reviewer can judge correctness from tests + helper signatures (EmittedName, BuildReservedClaimKeys, composeIssuanceClaims)
  • Failures surface at startup (Config.Validate()) with a clear message naming the bad prefix and the conflicting key

Security check

  • No secrets in code
  • All external inputs validated. The parser's reserved set now includes (1) the static RFC/OIDC/AuthGate-internal keys, (2) <prefix>_<logical> for every registry entry, (3) the bare logical names (domain / project / service_account) so callers cannot smuggle the legacy pre-prefix keys past it, and (4) the default-prefixed forms (extra_*) — reserved even on custom-prefix deployments so an un-migrated downstream consumer hardcoded to the default cannot be tricked.
  • Defense-in-depth at sign time. generateJWT strips the OIDC ID-token-only keys (nbf / azp / amr / acr / auth_time / nonce / at_hash), the bare logical names, and (on custom-prefix deployments) the default-prefixed forms — so a future regression that bypasses the parser still cannot land any of these in the signed JWT.
  • Server-attested <prefix>_domain still wins on collision: applyServerClaims writes it last, overriding caller- or client-supplied values.
  • OIDC discovery claims_supported excludes bare AND prefixed AuthGate-private claim names under default and custom prefixes (oidc_test.go exercises all three configurations).
  • JWT_DOMAIN semantics unchanged (server-attested, validated at startup, re-resolved on refresh).

Defense-in-depth coverage:

  • TestPrivateClaimPrefix_CallerCannotImpersonatePrefixedClaim — parser rejection + service-layer override for the configured prefix's composed key.
  • TestPrivateClaimPrefix_CallerCannotInjectBareLegacyName — bare names blocked at both layers.
  • TestPrivateClaimPrefix_CallerCannotInjectDefaultPrefixOnCustomDeploymentextra_* blocked at both layers when configured prefix is non-default.

Risk & rollback

Risk

  • Silent breakage of downstream JWT consumers that hardcoded claims["domain"]. Mitigation: prominent migration note in .env.example / docs/CONFIGURATION.md / docs/JWT_VERIFICATION.md / CLAUDE.md and this PR description; downstream integration smoke tests should run before merge.
  • Stale token cache after upgrade. Mitigation: documented operational requirement to flush the token cache on deploy. No code-level cache-key namespace bump in this PR (could be added later as a follow-up if operators want zero-touch cutover).
  • Misconfigured prefix at startup. Mitigation: Config.Validate() fails fast with a clear message naming the bad value or the colliding composed key.

Rollback

Revert the PR. Tokens minted under the new code carry only prefixed claims; downstream services that already migrated will need a coordinated revert. Treat this as a one-way door once consumers adopt — the practical rollback window is short.

Reviewer guide

Read carefully (line-by-line):

  • internal/config/config.govalidateJWTPrivateClaimPrefix (regex / length / trailing-_ / collision check) and the static reserved-keys list. Note the documented sync requirement with internal/token/reserved.go (the import cycle prevents sharing).
  • internal/token/reserved.goBuildReservedClaimKeys semantics; ValidateExtraClaims now takes a precomputed reserved set rather than reading a package-level map.
  • internal/services/token.gobuildClientClaims(client, prefix), buildServerClaims(cfg), composeIssuanceClaims (precedence caller → client → server unchanged).
  • internal/services/token_extra_claims_parser.goNewExtraClaimsParser precomputes the reserved set at construction time using the configured prefix.
  • internal/token/types.go — unexported privateClaims registry + PrivateClaimRegistry() accessor (returns a defensive copy) + EmittedName(prefix, logical) helper. Single source of truth for key composition; mutation from other packages is impossible by construction.

Spot-check OK:

  • Test files (signatures + the new token_private_claim_prefix_test.go matrix tell the story).
  • Doc updates in .env.example, docs/CONFIGURATION.md, docs/JWT_VERIFICATION.md, CLAUDE.md.

Suggested reviewer count: 2+ (core code) — including the token / OAuth module owner.

🤖 Generated with Claude Code

…ATE_CLAIM_PREFIX

- Add JWT_PRIVATE_CLAIM_PREFIX (default "extra") with startup validation
- Replace bare claim constants with PrivateClaim registry and EmittedName helper
- Compute reserved-key set at parser construction from prefix and registry
- Emit prefixed keys (extra_domain, extra_project, extra_service_account) on every grant
- Update discovery test to keep prefixed private claims out of claims_supported
- Document the prefix and the bare-name → prefixed-name migration

BREAKING CHANGE: server-attested private claims are no longer emitted under their bare names. Tokens now carry "extra_domain", "extra_project", and "extra_service_account" by default; deployments using JWT_PRIVATE_CLAIM_PREFIX=mtk emit "mtk_*". Downstream services that read claims["domain"] / claims["project"] / claims["service_account"] directly must update to the prefixed key (or the operator-chosen prefix) at the same time as the AuthGate upgrade. Token caches must be flushed on upgrade so pre-upgrade tokens with bare-name claims are not served from cache.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 2, 2026 04:33
@codecov
Copy link
Copy Markdown

codecov Bot commented May 2, 2026

Codecov Report

❌ Patch coverage is 73.10924% with 32 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/config/config.go 53.70% 20 Missing and 5 partials ⚠️
internal/token/types.go 33.33% 4 Missing ⚠️
internal/token/reserved.go 88.46% 2 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a deployment-configurable namespace prefix (JWT_PRIVATE_CLAIM_PREFIX, default "extra") for AuthGate server-attested private JWT claims, moving them from bare keys (domain, project, service_account) to prefixed keys (<prefix>_domain, <prefix>_project, <prefix>_service_account). It also centralizes the private-claim registry to reduce scattered wiring across emission, reserved-key checks, and tests.

Changes:

  • Add JWT_PRIVATE_CLAIM_PREFIX config support, defaults, and startup validation (shape/length/trailing _/collision guard).
  • Introduce token.PrivateClaims registry and token.EmittedName(prefix, logical) helper; update issuance paths to emit prefixed keys.
  • Update extra-claims reserved-key derivation and parser logic to be prefix-aware; refresh/flow tests and docs updated accordingly.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
internal/config/config.go Adds default/validation for JWT_PRIVATE_CLAIM_PREFIX, including regex/length and collision checks.
internal/config/config_test.go Ensures base test config includes the new prefix default.
internal/token/types.go Adds PrivateClaims registry and EmittedName composition helper.
internal/token/reserved.go Reworks reserved-claim handling to be prefix-derived via BuildReservedClaimKeys and updates ValidateExtraClaims signature.
internal/token/reserved_test.go Updates reserved-key and ValidateExtraClaims unit tests for prefix behavior.
internal/services/token.go Emits client/server private claims using the configured prefix during issuance composition.
internal/services/token_test.go Sets default prefix for tests that construct Config{} ad-hoc.
internal/services/token_extra_claims_parser.go Precomputes reserved-key set once per parser instance and validates using it.
internal/services/token_extra_claims_parser_test.go Ensures parser tests use default prefix config.
internal/services/token_extra_claims_test.go Updates claim-building and server-override tests to expect prefixed keys.
internal/services/token_domain_test.go Updates domain-claim tests to validate prefixed domain emission/omission.
internal/services/token_private_claim_prefix_test.go Adds an end-to-end-ish test matrix for default/custom prefix behavior and validation.
internal/token/local_test.go Updates provider injection tests to use prefixed keys.
internal/handlers/oidc_test.go Ensures discovery claims_supported doesn’t list private claims (bare or prefixed default).
docs/JWT_VERIFICATION.md Updates verification/migration guidance to prefixed private-claim keys.
docs/CONFIGURATION.md Documents new env var, validation rules, and migration notes.
.env.example Documents new env var, breaking change, and cache-flush guidance.
CLAUDE.md Updates configuration reference to include the new prefix behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/token/reserved.go Outdated
Comment thread internal/services/token_extra_claims_parser.go
Comment thread internal/config/config.go Outdated
Comment thread internal/token/types.go Outdated
Comment thread internal/services/token_private_claim_prefix_test.go Outdated
appleboy and others added 2 commits May 2, 2026 12:39
Replaces vendor-specific MTK references with the industry-standard
fictional placeholder "acme" across docs, comments, and test fixtures.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add bare logical names (domain/project/service_account) to BuildReservedClaimKeys so callers cannot smuggle legacy claim names past the parser
- Strip bare logical names in generateJWT as defense-in-depth so the strip survives any future parser bypass
- Default empty cfg.JWTPrivateClaimPrefix to DefaultJWTPrivateClaimPrefix in NewExtraClaimsParser to match production semantics for ad-hoc test configs
- Use DefaultJWTPrivateClaimPrefix constant in Load() instead of the literal "extra"
- Document PrivateClaims as read-only at runtime
- Rename TestJWTPrivateClaimPrefix_CollisionRejected to reflect what it asserts and add a real synthetic-injection collision test in the config package
- Add regression test locking in that bare legacy names cannot land in the signed JWT

Addresses Copilot review feedback on PR #182.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/CONFIGURATION.md Outdated
Comment thread CLAUDE.md Outdated
Comment thread internal/token/local.go Outdated
Comment thread internal/token/reserved_test.go Outdated
Comment thread internal/token/types.go Outdated
… list

- Unexport the private-claim registry as privateClaims and expose a defensive copy via PrivateClaimRegistry() so external packages cannot mutate the slice at runtime
- Precompute generateJWTStripList at package init so generateJWT no longer rebuilds the bare-name denylist on every issued token
- Iterate privateClaims in BuildReservedClaimKeys's bare-name test instead of hardcoding the legacy names, so adding a future PrivateClaim entry automatically keeps coverage in lockstep
- Sync docs/CONFIGURATION.md and CLAUDE.md with the actual reserved set, which now also includes the bare logical names plus the strip-at-sign defense

Addresses Copilot review feedback on PR #182.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/token/reserved_test.go
Comment thread internal/token/reserved.go Outdated
Comment thread internal/token/types.go
…loyments

- Always reserve the default-prefixed forms (extra_domain / extra_project / extra_service_account) in BuildReservedClaimKeys, even when the configured prefix is custom, so callers cannot smuggle them past the parser into the signed JWT
- Move the generateJWT strip list onto LocalTokenProvider (computed once at NewLocalTokenProvider) so it can be config-aware: when the configured prefix differs from the default, also strip the default-prefixed forms as defense-in-depth
- Default an empty JWTPrivateClaimPrefix to DefaultJWTPrivateClaimPrefix in NewLocalTokenProvider to match production semantics for ad-hoc Config{} test fixtures
- Eliminate the parallel staticReservedClaimKeys list in internal/token by exporting StaticReservedClaimKeys from internal/config (the leaf-most package, since token already imports config) so the runtime reserved-key derivation and the startup collision check share a single source of truth
- Add regression test locking in that callers cannot inject default-prefixed claims on a custom-prefix deployment

Addresses Copilot review feedback on PR #182.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/config/config.go Outdated
Comment thread internal/token/types.go Outdated
Comment thread docs/JWT_VERIFICATION.md Outdated
…ording

- Unexport StaticReservedClaimKeys as staticReservedClaimKeys + add a StaticReservedClaimKeys() accessor returning a defensive copy, so other packages cannot mutate the canonical reserved-claim list at runtime
- Rephrase the AuthGate-emitted private-claim registry: only <prefix>_domain is server-attested; <prefix>_project and <prefix>_service_account are owner-set per-client metadata (untrusted assertions). Updated PrivateClaim and privateClaims doc comments, .env.example, CLAUDE.md, docs/CONFIGURATION.md, and docs/JWT_VERIFICATION.md to reserve "server-attested" specifically for domain and use "AuthGate-emitted" / "AuthGate-private" for the broader category

Addresses Copilot review feedback on PR #182.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/handlers/oidc_test.go
Comment thread internal/handlers/oidc_test.go Outdated
Convert TestDiscovery_OmitsDomainEvenWhenSet to a table-driven test that
also exercises an explicit default prefix and a custom-prefix deployment
(acme), so the "AuthGate-private claim must not appear in claims_supported"
invariant is checked under every prefix shape. Also tighten the comment in
TestDiscovery_ReturnsCorrectMetadata to reflect what the assertion list
actually covers, pointing the custom-prefix coverage at the dedicated test.

Addresses Copilot review feedback on PR #182.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/config/config_test.go Outdated
Comment thread internal/services/token_test.go Outdated
…obal mutation

Extract the prefix-vs-reserved-key collision check from
validateJWTPrivateClaimPrefix into a pure detectPrefixCollision helper that
takes the logical-name and reserved-key lists as arguments. The synthetic
collision test now calls the helper directly with a one-off list, so it no
longer mutates the package-level jwtPrivateClaimLogicalNames slice and is
safe under t.Parallel() and concurrent Validate() calls.

Also stop mutating the caller-provided *config.Config in
createTestTokenService — apply the default prefix on a shallow copy so
fixtures shared across subtests don't observe a side-effected prefix.

Addresses Copilot review feedback on PR #182.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/config/config.go Outdated
Comment thread internal/token/reserved.go
…ateExtraClaims

- Make Config.Validate()'s prefix check treat an empty JWTPrivateClaimPrefix as "use the default" instead of erroring, matching the behavior already applied by Load() and the runtime layers (NewExtraClaimsParser, NewLocalTokenProvider, NewTokenService). Removes the inconsistency where ad-hoc Config{} fixtures would surface an empty-prefix error from Validate while the rest of the codebase silently substituted the default.
- ValidateExtraClaims now rejects a nil reserved map up front. A nil reserved map would silently disable reserved-key enforcement (nil-map lookups return ok=false), creating a footgun for future internal callers — explicit rejection makes the contract impossible to misuse.

Addresses Copilot review feedback on PR #182.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/config/config.go
Comment thread docs/CONFIGURATION.md Outdated
…x reservation

Address Copilot review comments:
1. Add TestPrivateClaimRegistryDrift (drift_test.go) that fails the build
   if config.jwtPrivateClaimLogicalNames diverges from token.privateClaims.
2. Document in CONFIGURATION.md that the default-prefixed forms (extra_domain,
   extra_project, extra_service_account) are always reserved even when
   JWT_PRIVATE_CLAIM_PREFIX is set to a custom value.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/token/local.go Outdated
Comment thread internal/token/reserved.go Outdated
…pKeys

Address Copilot review comments:
1. Reword local.go comment to accurately describe why prefixed private
   claims survive: computeStripList excludes them, not "written after".
2. Rename oidcStripKeys → jwtStripKeys since it contains both RFC 7519
   registered claims (nbf) and OIDC ID-token claims.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/services/token_extra_claims_test.go Outdated
Comment thread internal/token/reserved.go
… slice capacity

Address Copilot review comments:
1. Replace hardcoded "extra" with config.DefaultJWTPrivateClaimPrefix in
   TestBuildClientClaims to avoid test drift.
2. Size computeStripList capacity to 3*len(privateClaims) to account for
   the non-default-prefix branch without reallocation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/config/config.go Outdated
Comment thread internal/token/reserved_test.go
…eld doc

Document that empty JWTPrivateClaimPrefix is normalized to the default
("extra") at validation time, so operators and test authors are not
confused by the "1–15 chars" constraint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/config/config.go Outdated
Comment thread internal/config/config.go
- JWTDomain: clarify emitted key is "<prefix>_domain" not bare "domain"
- JWTPrivateClaimPrefix: clarify empty normalization is caller-side
  (Validate checks but does not mutate the field)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 20 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.

@appleboy appleboy merged commit b2dc884 into main May 2, 2026
21 checks passed
@appleboy appleboy deleted the feat/jwt-private-claim-prefix branch May 2, 2026 14:08
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