CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/mfa-flow-test-author

Build-an-X workflow for authoring automated tests covering multi-factor authentication flows: TOTP (RFC 6238, deterministic codes from a known secret + fixed time), HOTP (RFC 4226, counter-based), SMS/email OTP, WebAuthn/passkey registration and authentication via Chrome DevTools Protocol virtual authenticator (WebAuthn L2 §11), recovery codes, MFA enrollment, and step-up authentication challenges. Use when the team needs end-to-end MFA test coverage beyond what oauth-flow-test-author covers, or when introducing a new second factor to an existing auth surface.

74

Quality

93%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

webauthn-virtual-authenticator.mdreferences/

WebAuthn virtual-authenticator deep patterns

Extends Step 4 of SKILL.md. Reuses the virtual_auth_page fixture defined there (Playwright + CDP WebAuthn.addVirtualAuthenticator).

Ceremonies

WebAuthn Level 2 §7.1 registration: navigator.credentials.create() with PublicKeyCredentialCreationOptions makes the authenticator mint an asymmetric key pair; the server verifies the attestation. Authentication (§7.2) uses navigator.credentials.get() to produce a signed assertion. The CDP WebAuthn domain provides the virtual authenticator per WebAuthn L2 §11 ("User Agent Automation").

Authentication round-trip

def test_webauthn_authentication(virtual_auth_page, app_url):
    """Full round-trip: register then authenticate with the same passkey."""
    page, cdp, auth_id = virtual_auth_page
    # Register first
    page.goto(f"{app_url}/settings/passkeys")
    page.click("#register-passkey")
    page.wait_for_selector("#passkey-registered-confirmation")

    # Now authenticate
    page.goto(f"{app_url}/login")
    page.click("#passkey-login")
    page.wait_for_url(f"{app_url}/dashboard")
    assert "/dashboard" in page.url

User-verification enforcement

def test_webauthn_user_verification_required(virtual_auth_page, app_url, cdp):
    """When UV is disabled mid-session, server must reject the assertion."""
    page, cdp, auth_id = virtual_auth_page
    cdp.send("WebAuthn.setUserVerified",
             {"authenticatorId": auth_id, "isUserVerified": False})
    page.goto(f"{app_url}/login")
    page.click("#passkey-login")
    page.wait_for_selector("#login-error")
    assert page.is_visible("#login-error")

Server-side verification

Server-side verification uses @simplewebauthn/server (simplewebauthn.dev/docs/packages/server). verifyRegistrationResponse({ response, expectedChallenge, expectedOrigin, expectedRPID }) returns { verified, registrationInfo }. After authentication, verifyAuthenticationResponse({ response, expectedChallenge, expectedOrigin, expectedRPID, credential }) returns { verified, authenticationInfo: { newCounter } } - persist newCounter to prevent signature-counter replay.

SKILL.md

tile.json