zeroclaw-labs/zeroclaw · error

Expected type 'webauthn.create', got '{cd_type}'

Error message

Expected type 'webauthn.create', got '{cd_type}'

What it means

In finish_registration, the client_data_json of a registration response must carry type == "webauthn.create" per the WebAuthn registration ceremony. Any other value — most commonly "webauthn.get" — means the payload belongs to a different ceremony or was constructed incorrectly, and registration is rejected.

Source

Thrown at crates/zeroclaw-runtime/src/security/webauthn.rs:276

    /// Complete a WebAuthn registration ceremony.
    /// Validates the client response against the registration state,
    /// extracts the public key, and stores the credential.
    pub fn finish_registration(
        &self,
        reg_state: &RegistrationState,
        response: &RegisterCredentialResponse,
    ) -> Result<WebAuthnCredential> {
        // 1. Validate client data JSON
        let client_data_bytes = URL_SAFE_NO_PAD
            .decode(&response.client_data_json)
            .context("Invalid base64url in client_data_json")?;
        let client_data: serde_json::Value =
            serde_json::from_slice(&client_data_bytes).context("Invalid client data JSON")?;

        // Verify type
        let cd_type = client_data["type"].as_str().unwrap_or_default();
        anyhow::ensure!(
            cd_type == "webauthn.create",
            "Expected type 'webauthn.create', got '{cd_type}'"
        );

        // Verify challenge matches
        let cd_challenge = client_data["challenge"].as_str().unwrap_or_default();
        anyhow::ensure!(
            cd_challenge == reg_state.challenge,
            "Challenge mismatch in registration response"
        );

        // Verify origin
        let cd_origin = client_data["origin"].as_str().unwrap_or_default();
        anyhow::ensure!(
            cd_origin == self.config.rp_origin,
            "Origin mismatch: expected '{}', got '{cd_origin}'",
            self.config.rp_origin
        );

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Make the client call navigator.credentials.create() and send that exact response to the register-finish endpoint
  2. Keep registration and authentication response handling in separate code paths; never reuse payloads between them
  3. In tests, build client_data_json with type 'webauthn.create' and the challenge returned by register start

Example fix

// before: posting an authentication response to register finish
const resp = await navigator.credentials.get({ publicKey: authOptions });
await fetch('/register/finish', { method: 'POST', body: serialize(resp) });
// after
const resp = await navigator.credentials.create({ publicKey: regOptions });
await fetch('/register/finish', { method: 'POST', body: serialize(resp) });
Defensive patterns

Strategy: try-catch

Validate before calling

// optional client-side pre-check to give a clearer error than the server
const cd = JSON.parse(Array.from(atob(resp.response.clientDataJSON.replace(/-/g,'+').replace(/_/g,'/')), c => String.fromCharCode(c.charCodeAt(0))).split('').join(''));
if (cd.type !== 'webauthn.create') throw new Error('wrong ceremony: ensure navigator.credentials.create() response is sent to register finish');

Try / catch

in the HTTP handler wrapping finish_registration, catch the anyhow error and map ceremony-validation failures (type/challenge/origin messages) to HTTP 400 with the error text; do not retry the same payload

Prevention

When it happens

Trigger: Sending an authentication assertion (navigator.credentials.get result) to the registration finish endpoint; hand-built or test client_data_json using the wrong type string; a proxy or client library rewriting the payload.

Common situations: Frontend code mixing up the create/get response handlers and posting to the wrong endpoint; e2e tests synthesizing client data with copy-pasted fields; replayed or cached responses from a previous ceremony.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/c0c4c3ef05fbb97f. Report an issue: GitHub.