DPoP adoption skill recommends deterministic `jti` values derived from authorization codes
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
- Domain
- documentation, security
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
jtifor every DPoP proof, including authorization code exchanges, token refreshes, and nonce retries. - Avoid deterministic
jtiderivation from authorization codes. - Document that production callers supplying their own
jtimust 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
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from google/skills
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 79/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
Document registry default vs revision actually loaded by an agentMay be free again A pull request for this issue was closed without being merged. Openenhancement
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Similar issues
-
namespace
Difficulty 1/5 Under an hour Newbie friendliness 68/100
EclipseFdn/open-vsx.org#15604 ·
Maintainers usually reply within 1 day
-
app: scripts severity: low status: backlog type: bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
netbox-community/netbox-scripts#164 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Maintainers usually reply within 5 days
-
Public function to read participants.tsvPossibly taken @bruAristimunha claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Difficulty 1/5 1-3 hours Newbie friendliness 85/100
huggingface/tau#799 ·
Maintainers usually reply within 2 days