This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
securitycritical PriorityID: rfc-8705-mtls-sender-constrained-tokens

RFC 8705 OAuth 2.1 mTLS Certificate-Bound Token Verification

Enforces strict validation of RFC 8705 sender-constrained access tokens by binding tokens to the client's X.509 certificate established during mutual TLS (mTLS). Protected resource endpoints must compute the base64url-encoded SHA-256 thumbprint of the presented client certificate and verify its exact match against the token's confirmation claim (cnf.x5t#S256) to eliminate token replay vulnerabilities.

Prohibited Anti-Pattern: Accepting Certificate-Bound Tokens as Bearer Tokens Without Validating Transport-Layer Client Certificate Fingerprints

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: RFC 8705 OAuth 2.1 mTLS Certificate-Bound Token Verification - Enforces strict validation of RFC 8705 sender-constrained access tokens by binding tokens to the client's X.509 certificate established during mutual TLS (mTLS). Protected resource endpoints must compute the base64url-encoded SHA-256 thumbprint of the presented client certificate and verify its exact match against the token's confirmation claim (cnf.x5t#S256) to eliminate token replay vulnerabilities.
globs: src/auth/**/*.{ts,tsx,js}, src/middleware/**/*.{ts,tsx,js}, src/security/**/*.{ts,tsx,js}, src/gateway/**/*.{ts,tsx,js}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/rfc-8705-mtls-sender-constrained-tokens"
---

# RFC 8705 OAuth 2.1 mTLS Certificate-Bound Token Verification

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Accepting Certificate-Bound Tokens as Bearer Tokens Without Validating Transport-Layer Client Certificate Fingerprints

## System Constraints
You are a Principal Security Architect enforcing RFC 8705 and OAuth 2.1 sender-constrained mutual TLS token invariants. In your reviews and generated code, access tokens containing confirmation (cnf) claims MUST be verified against the client certificate presented at the transport layer. Any attempt to authorize requests with unverified certificate thumbprints, downgrade to bearer semantics, or blindly trust forward headers without gateway mutual authentication is strictly prohibited.

## Strict Guidelines
- Engineers MUST ALWAYS extract the client X.509 certificate from the active TLS session (or a cryptographically verified mutual TLS upstream proxy header) and compute its DER SHA-256 thumbprint.
- Engineers MUST base64url-encode the raw SHA-256 certificate digest without padding, strictly adhering to RFC 8705 Section 3.1.
- Services MUST verify that the token's 'cnf.x5t#S256' claim strictly matches the computed certificate thumbprint using constant-time comparison before authorizing the request.
- Services MUST reject requests with HTTP 401 Unauthorized ('invalid_token') if a certificate-bound token is presented over a connection without a client certificate, or if the thumbprint check fails.
- Engineers MUST NOT trust incoming client certificate headers (e.g., 'X-Client-Cert') unless the upstream reverse proxy connection is mutually authenticated and isolated within a trusted internal network.
- Components NEVER fall back to standard bearer authorization if an access token contains a 'cnf' claim.

## Bad vs Good Implementations
### RFC 8705 Certificate-Bound Token Thumbprint Verification

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The middleware validates the cryptographic signature of the token but ignores the 'cnf' claim and TLS transport binding. If a sender-constrained token is stolen, an adversary can replay it over standard TLS without possessing the associated private key.
```typescript
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';

export function verifyToken(req: Request, res: Response, next: NextFunction) {
  const authHeader = req.headers.authorization;
  if (!authHeader?.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'unauthorized' });
  }

  const token = authHeader.substring(7);
  try {
    // VULNERABILITY: Validates JWT signature but completely ignores
    // the 'cnf' confirmation claim and client TLS certificate.
    // An attacker with a stolen token can replay it from any origin.
    const decoded = jwt.verify(token, process.env.JWT_PUBLIC_KEY!) as any;
    req.user = decoded;
    return next();
  } catch (err) {
    return res.status(401).json({ error: 'invalid_token' });
  }
}
```

#### Production Standard (Correct)
> **Standard**: The middleware extracts the presented client certificate from the TLS session, computes the SHA-256 thumbprint in base64url format per RFC 8705 Section 3.1, and uses constant-time comparison against payload.cnf['x5t#S256']. Replayed tokens without the private key cannot complete the mTLS handshake.
```typescript
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import crypto from 'node:crypto';
import { TLSSocket } from 'node:tls';

interface CnfClaim {
  'x5t#S256'?: string;
}

interface BoundJwtPayload extends jwt.JwtPayload {
  cnf?: CnfClaim;
}

function computeCertThumbprint(derCert: Buffer): string {
  return crypto
    .createHash('sha256')
    .update(derCert)
    .digest('base64url');
}

export function verifyMtlsBoundToken(req: Request, res: Response, next: NextFunction) {
  const authHeader = req.headers.authorization;
  if (!authHeader?.startsWith('Bearer ')) {
    res.setHeader('WWW-Authenticate', 'error="invalid_token", error_description="Missing authorization header"');
    return res.status(401).json({ error: 'invalid_token' });
  }

  const token = authHeader.substring(7);
  let payload: BoundJwtPayload;

  try {
    payload = jwt.verify(token, process.env.JWT_PUBLIC_KEY!, {
      algorithms: ['RS256', 'ES256']
    }) as BoundJwtPayload;
  } catch {
    res.setHeader('WWW-Authenticate', 'error="invalid_token", error_description="Token signature verification failed"');
    return res.status(401).json({ error: 'invalid_token' });
  }

  // RFC 8705 Section 3: Check for certificate-bound token
  const expectedThumbprint = payload.cnf?.['x5t#S256'];
  if (!expectedThumbprint) {
    // Reject if policy enforces sender-constrained tokens only
    res.setHeader('WWW-Authenticate', 'error="invalid_token", error_description="Missing cnf claim in token"');
    return res.status(401).json({ error: 'invalid_token' });
  }

  // Retrieve client certificate from TLS handshake
  const tlsSocket = req.socket as TLSSocket;
  const peerCert = tlsSocket.getPeerCertificate ? tlsSocket.getPeerCertificate(true) : null;

  if (!peerCert || !peerCert.raw) {
    res.setHeader('WWW-Authenticate', 'error="invalid_token", error_description="mTLS client certificate required"');
    return res.status(401).json({ error: 'invalid_token' });
  }

  const actualThumbprint = computeCertThumbprint(peerCert.raw);
  const expectedBuffer = Buffer.from(expectedThumbprint, 'utf8');
  const actualBuffer = Buffer.from(actualThumbprint, 'utf8');

  // Constant-time comparison to prevent timing side-channels
  if (
    expectedBuffer.length !== actualBuffer.length ||
    !crypto.timingSafeEqual(expectedBuffer, actualBuffer)
  ) {
    res.setHeader('WWW-Authenticate', 'error="invalid_token", error_description="Certificate thumbprint mismatch"');
    return res.status(401).json({ error: 'invalid_token' });
  }

  req.user = payload;
  return next();
}
```

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 8705 OAuth 2.1 mTLS Certificate-Bound Token Verification

RFC 8705 OAuth 2.1 mTLS Certificate-Bound Token Verification defines an industrial-grade behavioral standard for security engineering. Enforces strict validation of RFC 8705 sender-constrained access tokens by binding tokens to the client's X.509 certificate established during mutual TLS (mTLS). Protected resource endpoints must compute the base64url-encoded SHA-256 thumbprint of the presented client certificate and verify its exact match against the token's confirmation claim (cnf.x5t#S256) to eliminate token replay vulnerabilities. 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 Certificate-Bound Tokens as Bearer Tokens Without Validating Transport-Layer Client Certificate Fingerprints 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 Certificate-Bound Tokens as Bearer Tokens Without Validating Transport-Layer Client Certificate FingerprintsCritical
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

Engineers MUST ALWAYS extract the client X.509 certificate from the active TLS session (or a cryptographically verified mutual TLS upstream proxy header) and compute its DER SHA-256 thumbprint.

Engineers MUST ALWAYS extract the client X.509 certificate from the active TLS session (or a cryptographically verified mutual TLS upstream proxy header) and compute its DER SHA-256 thumbprint.

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

Engineers MUST base64url-encode the raw SHA-256 certificate digest without padding, strictly adhering to RFC 8705 Section 3.1.

Engineers MUST base64url-encode the raw SHA-256 certificate digest without padding, strictly adhering to RFC 8705 Section 3.1.

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

Services MUST verify that the token's 'cnf.x5t#S256' claim strictly matches the computed certificate thumbprint using constant-time comparison before authorizing the request.

Services MUST verify that the token's 'cnf.x5t#S256' claim strictly matches the computed certificate thumbprint using constant-time comparison before authorizing the request.

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

Services MUST reject requests with HTTP 401 Unauthorized ('invalid_token') if a certificate-bound token is presented over a connection without a client certificate, or if the thumbprint check fails.

Services MUST reject requests with HTTP 401 Unauthorized ('invalid_token') if a certificate-bound token is presented over a connection without a client certificate, or if the thumbprint check fails.

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

Engineers MUST NOT trust incoming client certificate headers (e.g., 'X-Client-Cert') unless the upstream reverse proxy connection is mutually authenticated and isolated within a trusted internal network.

Engineers MUST NOT trust incoming client certificate headers (e.g., 'X-Client-Cert') unless the upstream reverse proxy connection is mutually authenticated and isolated within a trusted internal network.

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

Components NEVER fall back to standard bearer authorization if an access token contains a 'cnf' claim.

Components NEVER fall back to standard bearer authorization if an access token contains a 'cnf' claim.

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 8705 OAuth 2.1 mTLS Certificate-Bound Token Verification critical for AI coding assistants?

Enforces strict validation of RFC 8705 sender-constrained access tokens by binding tokens to the client's X.509 certificate established during mutual TLS (mTLS). Protected resource endpoints must compute the base64url-encoded SHA-256 thumbprint of the presented client certificate and verify its exact match against the token's confirmation claim (cnf.x5t#S256) to eliminate token replay vulnerabilities. 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 Certificate-Bound Tokens as Bearer Tokens Without Validating Transport-Layer Client Certificate Fingerprints) 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