Skip to content

[C2S] Add DPoP (RFC 9449) support for OAuth token binding#2941

Draft
pfefferle wants to merge 1 commit intoadd/c2s-supportfrom
add/dpop-support
Draft

[C2S] Add DPoP (RFC 9449) support for OAuth token binding#2941
pfefferle wants to merge 1 commit intoadd/c2s-supportfrom
add/dpop-support

Conversation

@pfefferle
Copy link
Member

Fixes #

Proposed changes:

  • Add DPoP (Demonstrating Proof of Possession, RFC 9449) support for the C2S OAuth implementation. This cryptographically binds access tokens to a client's key pair, preventing token theft and replay attacks.
  • DPoP is fully opt-in: clients that include a DPoP proof header during token issuance get DPoP-bound tokens; clients that don't get regular Bearer tokens with no behavior change.
  • Self-contained implementation with no external JWT library — uses PHP's OpenSSL extension directly, compatible with PHP 7.2+.
  • Supports ES256 (ECDSA P-256) and RS256 signing algorithms.

Key changes:

  • New DPoP class (includes/oauth/class-dpop.php) — JWT decode, JWK thumbprint (RFC 7638), JWK-to-PEM conversion, DPoP proof validation with jti replay protection
  • Token class — stores dpop_jkt binding, returns token_type: DPoP, preserves binding through refresh, includes cnf.jkt in introspection
  • Server class — accepts Authorization: DPoP scheme, validates proofs on resource access, advertises dpop_signing_alg_values_supported in metadata, adds DPoP to CORS headers
  • OAuth_Controller — validates DPoP proofs at token endpoint for both auth code and refresh grants, verifies key consistency on refresh

Other information:

  • Have you written new tests for your changes, if applicable?

Testing instructions:

  • Run existing OAuth tests to verify no regressions: npm run env-test -- --group=oauth
  • Run DPoP-specific tests: npm run env-test -- --filter=DPoP
  • Verify server metadata includes dpop_signing_alg_values_supported: curl <site>/wp-json/activitypub/1.0/oauth/authorization-server-metadata | jq .dpop_signing_alg_values_supported
  • Existing Bearer token flows should work identically (backward compatible)

Changelog entry

  • Automatically create a changelog entry from the details below.
Changelog Entry Details

Significance

  • Patch
  • Minor
  • Major

Type

  • Added - for new features
  • Changed - for changes in existing functionality
  • Deprecated - for soon-to-be removed features
  • Removed - for now removed features
  • Fixed - for any bug fixes
  • Security - in case of vulnerabilities

Message

Add support for DPoP (RFC 9449) to protect OAuth tokens from theft and replay.

Implement Demonstrating Proof of Possession to cryptographically bind
access tokens to a client's key pair, preventing token theft and replay.

DPoP is fully opt-in: clients that include a DPoP proof header during
token issuance get DPoP-bound tokens; clients that don't get regular
Bearer tokens with no behavior change.

- Add self-contained DPoP proof validator (ES256, RS256) with no
  external JWT library dependency
- Bind tokens to JWK thumbprint (RFC 7638) at issuance
- Validate DPoP proofs on resource access for bound tokens
- Preserve DPoP binding through token refresh
- Advertise dpop_signing_alg_values_supported in server metadata
- Add DPoP to CORS allowed headers
- Add 27 tests covering proof validation, key binding, and edge cases
@pfefferle pfefferle self-assigned this Feb 19, 2026
@pfefferle pfefferle requested a review from a team February 19, 2026 09:11
@pfefferle pfefferle changed the title Add DPoP (RFC 9449) support for OAuth token binding [C2S] Add DPoP (RFC 9449) support for OAuth token binding Feb 19, 2026
@pfefferle pfefferle added this to the ActivityPub API milestone Feb 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants