This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
securitycritical PriorityID: rfc-9449-dpop-asymmetric-token-binding

RFC 9449 DPoP Asymmetric Token Binding & Anti-Replay Guardrail

Enforces RFC 9449 Demonstrating Proof-of-Possession (DPoP) at application and microservice boundaries to cryptographically bind access tokens to client-held private keys. Prevents token replay, credential theft via log leakage, and unauthorized proxying by requiring strict verification of the dpop+jwt proof header, HTTP target binding (htm/htu), access token hash (ath), and nonces.

Prohibited Anti-Pattern: Accepting Unbound Bearer Tokens or Incompletely Validated DPoP Proofs Lacking ATH and Replay Nonces

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: RFC 9449 DPoP Asymmetric Token Binding & Anti-Replay Guardrail - Enforces RFC 9449 Demonstrating Proof-of-Possession (DPoP) at application and microservice boundaries to cryptographically bind access tokens to client-held private keys. Prevents token replay, credential theft via log leakage, and unauthorized proxying by requiring strict verification of the dpop+jwt proof header, HTTP target binding (htm/htu), access token hash (ath), and nonces.
globs: src/**/*.{ts,tsx}, lib/**/*.{ts,tsx}, middleware/**/*.{ts,tsx}, api/**/*.{ts,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/rfc-9449-dpop-asymmetric-token-binding"
---

# RFC 9449 DPoP Asymmetric Token Binding & Anti-Replay Guardrail

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Accepting Unbound Bearer Tokens or Incompletely Validated DPoP Proofs Lacking ATH and Replay Nonces

## System Constraints
You are a Principal Security Architect enforcing RFC 9449 DPoP (Demonstrating Proof-of-Possession). You must ensure that all HTTP service boundaries, API clients, and OAuth 2.0 / OIDC integrations strictly reject bearer tokens without proof-of-possession, generate valid asymmetric proofs with dynamic jti, htm, and htu claims, enforce the access token hash (ath), and maintain strict temporal and replay nonce controls.

## Strict Guidelines
- Services MUST NEVER accept authorization schemes using standard 'Bearer' tokens when protected by DPoP; requests MUST supply the 'DPoP <access-token>' scheme in the Authorization header along with a separate 'DPoP' proof header.
- The DPoP proof JWT header MUST strictly declare typ='dpop+jwt', use an approved asymmetric algorithm (e.g., ES256, EdDSA, RS256), and embed the public key in the 'jwk' header WITHOUT any private key material (d, p, q, dp, dq, qi).
- Resource Servers MUST compute and verify the Access Token Hash ('ath') claim inside the DPoP payload using base64url(SHA-256(access_token)) to eliminate token substitution attacks.
- Resource Servers MUST validate that the 'htm' (HTTP Method) and 'htu' (HTTP Target URI without query parameters or fragments) claims strictly match the normalized incoming request URL and verb.
- Clients and Resource Servers MUST enforce maximum clock skew (maximum 60-300 seconds TTL for the 'iat' claim) and maintain a distributed idempotency store (e.g., Redis) for 'jti' values within the active window to prevent replay attacks.
- Resource Servers MUST challenge expired or missing nonces with a 401 response containing 'WWW-Authenticate: DPoP error="use_dpop_nonce"' and 'DPoP-Nonce: <server-nonce>', and clients MUST retry once with the issued nonce.

## Bad vs Good Implementations
### Resource Server Verification of RFC 9449 DPoP Header & Access Token Hash (ATH)

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Accepts static Bearer tokens vulnerable to MITM interception, proxy compromise, and lateral replay. Lacks RFC 9449 DPoP proof header verification, accepts tokens without cryptographically binding them to the caller's key, and omits HTTP method/URI and nonce validations.
```typescript
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';

// VULNERABLE: Relies on Bearer tokens or blind JWT verification without
// verifying asymmetric key binding, HTTP context (htm/htu), or token hash (ath).
export async function authenticateToken(req: Request, res: Response, next: NextFunction) {
  const authHeader = req.headers['authorization'];
  if (!authHeader?.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'Missing or invalid token' });
  }

  const token = authHeader.split(' ')[1];
  try {
    // Bearer token can be exfiltrated and replayed by any adversary
    const decoded = jwt.decode(token) as { sub: string };
    (req as any).user = decoded;
    next();
  } catch (err) {
    return res.status(403).json({ error: 'Token invalid' });
  }
}
```

#### Production Standard (Correct)
> **Standard**: Implements RFC 9449 compliance by demanding the 'DPoP' scheme, verifying the 'dpop+jwt' header typ, importing the asymmetric JWK, validating 'htm' and 'htu' against the current route, asserting base64url(sha256(token)) matches 'ath', and protecting against replay attacks with a 'jti' cache.
```typescript
import { Request, Response, NextFunction } from 'express';
import { createHash } from 'node:crypto';
import * as jose from 'jose';

interface ReplayCache {
  has(jti: string): Promise<boolean>;
  set(jti: string, ttlSeconds: number): Promise<void>;
}
declare const replayCache: ReplayCache;

export async function verifyDPoP(req: Request, res: Response, next: NextFunction) {
  const authHeader = req.headers['authorization'];
  const dpopProof = req.headers['dpop'] as string | undefined;

  if (!authHeader?.startsWith('DPoP ') || !dpopProof) {
    res.setHeader('WWW-Authenticate', 'DPoP error="invalid_token"');
    return res.status(401).json({ error: 'DPoP authorization and proof headers required' });
  }

  const accessToken = authHeader.slice(5).trim();

  try {
    const unverifiedHeader = jose.decodeProtectedHeader(dpopProof);
    if (unverifiedHeader.typ !== 'dpop+jwt' || !unverifiedHeader.jwk) {
      return res.status(400).json({ error: 'Invalid DPoP header typ or missing jwk' });
    }

    const publicKey = await jose.importJWK(unverifiedHeader.jwk, unverifiedHeader.alg);
    const { payload } = await jose.jwtVerify(dpopProof, publicKey, {
      algorithms: ['ES256', 'RS256', 'EdDSA'],
      clockTolerance: '60 seconds'
    });

    const expectedUri = `${req.protocol}://${req.get('host')}${req.baseUrl}${req.path}`;
    if (payload.htm !== req.method.toUpperCase() || payload.htu !== expectedUri) {
      return res.status(400).json({ error: 'DPoP proof htm/htu mismatch' });
    }

    const expectedAth = createHash('sha256').update(accessToken).digest('base64url');
    if (payload.ath !== expectedAth) {
      return res.status(400).json({ error: 'Access token hash (ath) mismatch' });
    }

    const jti = payload.jti as string;
    if (!jti || await replayCache.has(jti)) {
      return res.status(401).json({ error: 'DPoP proof replayed or missing jti' });
    }
    await replayCache.set(jti, 300);

    (req as any).dpopJwk = unverifiedHeader.jwk;
    next();
  } catch (error) {
    return res.status(401).json({ error: 'Cryptographic DPoP verification failed' });
  }
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: RFC 9449 DPoP Asymmetric Token Binding & Anti-Replay Guardrail

RFC 9449 DPoP Asymmetric Token Binding & Anti-Replay Guardrail defines an industrial-grade behavioral standard for security engineering. Enforces RFC 9449 Demonstrating Proof-of-Possession (DPoP) at application and microservice boundaries to cryptographically bind access tokens to client-held private keys. Prevents token replay, credential theft via log leakage, and unauthorized proxying by requiring strict verification of the dpop+jwt proof header, HTTP target binding (htm/htu), access token hash (ath), and nonces. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Accepting Unbound Bearer Tokens or Incompletely Validated DPoP Proofs Lacking ATH and Replay Nonces Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftAccepting Unbound Bearer Tokens or Incompletely Validated DPoP Proofs Lacking ATH and Replay NoncesCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Services MUST NEVER accept authorization schemes using standard 'Bearer' tokens when protected by DPoP

Services MUST NEVER accept authorization schemes using standard 'Bearer' tokens when protected by DPoP; requests MUST supply the 'DPoP <access-token>' scheme in the Authorization header along with a separate 'DPoP' proof header.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

The DPoP proof JWT header MUST strictly declare typ='dpop+jwt', use an approved asymmetric algorithm (e.g., ES256, EdDSA, RS256), and embed the public key in the 'jwk' header WITHOUT any private key material (d, p, q, dp, dq, qi).

The DPoP proof JWT header MUST strictly declare typ='dpop+jwt', use an approved asymmetric algorithm (e.g., ES256, EdDSA, RS256), and embed the public key in the 'jwk' header WITHOUT any private key material (d, p, q, dp, dq, qi).

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Resource Servers MUST compute and verify the Access Token Hash ('ath') claim inside the DPoP payload using base64url(SHA-256(access_token)) to eliminate token substitution attacks.

Resource Servers MUST compute and verify the Access Token Hash ('ath') claim inside the DPoP payload using base64url(SHA-256(access_token)) to eliminate token substitution attacks.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Resource Servers MUST validate that the 'htm' (HTTP Method) and 'htu' (HTTP Target URI without query parameters or fragments) claims strictly match the normalized incoming request URL and verb.

Resource Servers MUST validate that the 'htm' (HTTP Method) and 'htu' (HTTP Target URI without query parameters or fragments) claims strictly match the normalized incoming request URL and verb.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Clients and Resource Servers MUST enforce maximum clock skew (maximum 60-300 seconds TTL for the 'iat' claim) and maintain a distributed idempotency store (e.g., Redis) for 'jti' values within the active window to prevent replay attacks.

Clients and Resource Servers MUST enforce maximum clock skew (maximum 60-300 seconds TTL for the 'iat' claim) and maintain a distributed idempotency store (e.g., Redis) for 'jti' values within the active window to prevent replay attacks.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
6

Resource Servers MUST challenge expired or missing nonces with a 401 response containing 'WWW-Authenticate

Resource Servers MUST challenge expired or missing nonces with a 401 response containing 'WWW-Authenticate: DPoP error="use_dpop_nonce"' and 'DPoP-Nonce: <server-nonce>', and clients MUST retry once with the issued nonce.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is RFC 9449 DPoP Asymmetric Token Binding & Anti-Replay Guardrail critical for AI coding assistants?

Enforces RFC 9449 Demonstrating Proof-of-Possession (DPoP) at application and microservice boundaries to cryptographically bind access tokens to client-held private keys. Prevents token replay, credential theft via log leakage, and unauthorized proxying by requiring strict verification of the dpop+jwt proof header, HTTP target binding (htm/htu), access token hash (ath), and nonces. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Accepting Unbound Bearer Tokens or Incompletely Validated DPoP Proofs Lacking ATH and Replay Nonces) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

RFC