DPoP adoption skill recommends deterministic `jti` values derived from authorization codes

Open Beginner friendly
#236 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
68/100
Issue type
Documentation
Clarity
Clearly specified
Activity status
Active
Tech stack
python

Research direction

Read skills/identity/dpop-adoption/SKILL.md, the affected file named in the issue. Update its guidance so each DPoP proof gets a fresh random jti, caller supplied identifiers are documented as requiring uniqueness, and client uniqueness is not presented as sufficient replay protection. Done when the skill covers authorization code exchanges, refreshes, nonce retries, and the need for server side replay validation.

Written by the indexing model from the issue text.

Description

Description

The DPoP adoption skill currently recommends deriving the jti claim from the authorization code:

jti = await calculateAuthCodeJti(authCode)
// calculateAuthCodeJti(authCode) = base64url(sha256(authCode))

This produces the same jti whenever a proof is generated for the same authorization code.

RFC 9449 Section 4.2 requires a unique jti for each DPoP proof. The current guidance also allows caller-provided identifiers to be reused without warning, while generating a random identifier only as a fallback.

The authorization code is already included in the OAuth token request. Deriving the proof identifier from it is not necessary for DPoP token binding and can undermine the uniqueness requirement.

Suggested changes

  • Generate a fresh, cryptographically random jti for every DPoP proof, including authorization code exchanges, token refreshes, and nonce retries.
  • Avoid deterministic jti derivation from authorization codes.
  • Document that production callers supplying their own jti must ensure uniqueness.
  • Clarify that client-side identifier uniqueness alone does not guarantee replay prevention; server-side validation is also required.

Proposed fix

I prepared a documentation-only fix in my fork:

https://github.com/tanahiro2010/google-skills/commit/4d2694d452cc9355b9a45742bcc5ca92fe3e42dd

I'm opening this issue rather than a pull request in accordance with the repository's contribution policy, which currently does not accept external PRs.

Additional context: Empirical testing

I previously investigated DPoP proof replay behavior against Google's OAuth token endpoint.

During testing, I observed that an identical signed DPoP proof could be reused for up to approximately 59 minutes under the tested conditions, despite the documented replay-protection behavior.

I documented the methodology and observations in a technical article:

Technical write-up: https://blog.tanahiro2010.com/articles/google-oauth-dpop/
https://dev.to/tanahiro2010/i-tested-googles-dpop-implementation-the-documentation-told-a-different-story-38i6

I also submitted these observations through Google's security reporting channel. Google reviewed the report but did not classify it as a security vulnerability, as no concrete security impact was demonstrated.

This issue is separate from that security assessment. The primary concern here is that the skill recommends deterministic jti generation, which conflicts with the per-proof uniqueness requirement in RFC 9449.

The empirical findings are included only as additional context for why client implementations should not assume specific server-side replay-rejection behavior.

References

Dominant language
Python
Stars
23.1k
Forks
1.9k
PR merge metrics
No merged PRs in 30d

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from google/skills

All issues in google/skills

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.