Spaces:
Running
Running
WebAuthn Human-in-the-Loop Attestation Integration Notes
Standards References
- W3C WebAuthn Level 3: https://www.w3.org/TR/webauthn-3/
- FIDO2 CTAP2: https://fidoalliance.org/specs/fido-v2.0-ps-20190130/
- Yubico Signing Pattern: https://developers.yubico.com/WebAuthn/Concepts/Using_WebAuthn_for_Signing.html
- COSE Algorithms: https://www.iana.org/assignments/cose/cose.xhtml
- SimpleWebAuthn: https://simplewebauthn.dev/docs/
Architecture
Cursor/Claude operator interface
│ sensitive action detected
▼
mcpWebAuthnApprove() → returns AuthenticationOptions to browser
│
▼
Browser: startAuthentication() from @simplewebauthn/browser
Touch ID / FIDO2 gesture
│
▼
WebAuthn assertion (clientDataJSON + authenticatorData + ECDSA-P256 sig)
│
▼
verifyAssertionAndEmitDSSE() → WebAuthnDSSESignature
│
▼
augmentDSSEWithWebAuthn() → DSSE envelope with 2 signatures:
1. HMAC-SHA256 (automated, machine identity)
2. WebAuthn ECDSA-P256 (human, biometric/PIN-bound)
│
▼
augmentReceiptWithWebAuthn() → JSONL receipt + humanAttestation block
│
▼
submitDSSEToRekor() → Rekor entry with dual-signature envelope
MCP Tool Integration
Two new MCP tools exposed to Cursor/Claude users:
webauthn_register
server.tool("webauthn_register", {
operatorDID: z.string(),
userName: z.string(),
}, async ({ operatorDID, userName }) => {
const opts = mcpWebAuthnRegister(szlRP, operatorDID, userName);
// Return to browser for startRegistration(@simplewebauthn/browser)
return { registrationOptions: opts };
});
webauthn_approve
server.tool("webauthn_approve", {
operatorDID: z.string(),
receiptId: z.string(),
}, async ({ operatorDID, receiptId }) => {
const receipt = await lookupReceipt(receiptId);
const opts = mcpWebAuthnApprove(szlRP, operatorDID, receipt.envelope.payload);
// Return to browser for startAuthentication()
// After browser completes gesture, call verify_assertion tool:
return { signingOptions: opts, pendingApproval: receiptId };
});
Sensitive Action Policy (when to require WebAuthn)
Configure in a11oy/src/webauthn/policy.ts:
| Action | Require WebAuthn? | Reason |
|---|---|---|
deploy to production |
YES | Irreversible side effect |
key_rotation |
YES | Cryptographic identity change |
federation_cross_ref |
YES | Cross-org trust boundary |
validate |
NO | Automated quality gate |
audit_export |
YES | Data sovereignty |
deploy to staging |
NO | Reversible test env |
STAGED-ADVISORY: Production Dependencies
# Server-side (Node.js Pepr/MCP):
npm install @simplewebauthn/server
# Browser-side (Cursor plugin / web UI):
npm install @simplewebauthn/browser
# Replace dev stubs:
# verifyRegistration → verifyRegistrationResponse from @simplewebauthn/server
# verifyAssertionAndEmitDSSE → verifyAuthenticationResponse from @simplewebauthn/server
Security Properties
- Human presence: UP flag verified — physical authenticator interaction required
- User verification: UV flag verified — biometric/PIN required, not just tap
- Replay prevention: signCount monotonically increasing; counter replay rejected
- Payload binding: challenge = SHA-256(DSSE payload) — assertion is cryptographically bound to the specific receipt being approved, not just any receipt
- Origin binding: clientDataJSON.origin checked — prevents cross-site relay attacks
- Additive, not substitutive: WebAuthn sig appended alongside HMAC; both required for "dual-control" governance actions