Why is my nonce failing to verify when passed over a rest request?

I am verifying a nonce over a WP REST endpoint yet it is failing to verify. I have triple checked my nonce names, so I don’t know why this would fail. I don’t know if I need to add something for the user, but I am passing _wpnonce in the body of the ajax request, and then scooping it up in the params.

I have checked that the values match in the console.

Here is the php responsible for generating the form, with the nonce field:

   $nonce_field = wp_nonce_field( 'nonce-sparkloop', '_wpnonce', true,  true );

        $output = "<div id=\"".$form_wrapper_id."\" class=\"sparkloop-forms--form-wrapper\">";
        if($recaptcha_key = $this->get_recaptchka_api_key()) {
            $output .= "
                <form id=\"sparkLoopForm\" class=\"sparkloop-forms--form\" data-count=\"".$count."\">
                    <div class=\"sparkloop-form--input-element\">
                        <label>Email <span class=\"required\">*</span></label>
                        <input
                        required
                        id=\"email\"
                        name=\"email\"
                        type=\"email\"
                        placeholder=\"Email\"
                        value=\"\" />

                        $nonce_field

                        <input
                        id=\"_post_id\"
                        type=\"hidden\"
                        name=\"_post_id\"
                        value=\"".$post_id."\"
                        >

                        <input
                        id=\"_permalink\"
                        type=\"hidden\"
                        name=\"_permalink\"
                        value=\"".$permalink."\"
                        >

                        <button
                        type=\"submit\"
                        data-recaptcha-key=". $recaptcha_key .">
                            Sign up
                        </button>
                    </div>
                </form>
        ";

The JS

console.log("sparkloop forms")

addEventListener('DOMContentLoaded', function() {
    const sparkLoopForms = document.querySelectorAll('.sparkloop-forms--form');
    const site_url = window.ffp_site_data?.site_url;
    const assets_url = window.ffp_site_data?.assets_url;
    const re_key = window.ffp_site_data?.recaptcha_key;

    console.log('sparkloop-forms-event-listener-fired')
    console.log(sparkLoopForms)

    if(sparkLoopForms) {
        sparkLoopForms.forEach(sparkLoopForm => {
            sparkLoopForm.addEventListener('submit', (e) => {
                e.preventDefault();
                let count = e.target.getAttribute('data-count');
                let formWrapper = document.getElementById('sparkLoopForm-' + count)

                grecaptcha.ready(function () {
                    grecaptcha.execute(re_key, {action: 'submit'}).then(function (token) {
                        e.preventDefault();
                        const url = site_url + '/wp-json/sparkloopforms/v1/add-contact';
                        const formData = new FormData(sparkLoopForm);
                        const email = formData.get('email');
                        const _wpnonce = document.getElementById('_wpnonce');
                        const nonceValue = _wpnonce.value;
                        const _post_id = document.getElementById('_post_id');
                        const postID = _post_id.value;
                        const _permalink = document.getElementById('_permalink');
                        const permalink = _permalink.value;

                        data = {
                            email: email,
                            _wpnonce: nonceValue,
                            _post_id: postID,
                            _permalink: permalink
                        }

                        if (formWrapper) {
                            formWrapper.innerHTML = `
                                <div class="sparkloop-forms--loading">
                                    <div class="sparkloop-forms--loading-inner">
                                        <img style="max-width: 30px; height: auto;" src="${assets_url}images/loading.gif">
                                    </div>
                                </div>
                            `;
                        }

                        fetch(url, {
                            method: "POST",
                            headers: {
                                "Content-Type": "application/json",
                            },
                            body: JSON.stringify(data)
                        })
                            .then(response => response.json())
                            .then(data => {
                                let formWrapper = document.getElementById('sparkLoopForm-' + count);
                                let statusClass, statusMessage;

                                if (data.errors) {
                                    statusClass = "sparkloop-forms--error";
                                    statusMessage = "There has been an error.";
                                    console.log(data.errors[0].message)
                                } else if (data.successfully_added_subscriber) {
                                    statusClass = "sparkloop-forms--success";
                                    statusMessage = "Success! Thank you for signing up";
                                } else {
                                    console.log(data)
                                    statusClass = "sparkloop-forms--error";
                                    statusMessage = "Unknown error occurred.";
                                }

                                if (formWrapper) {
                                    formWrapper.innerHTML = `
                                <div class="sparkloop_forms--response">
                                    <p class="${statusClass}">${statusMessage}</p>
                                    <p>${data.message || ""}</p>
                                </div>
                                `;
                                }
                                //
                                // console.log("Success: ", data)
                            })
                            .catch((error) => {
                                console.log("Error: ", error)
                            });
                    })
                })
            });
        });
    }
});


console.log(new XMLHttpRequest())

The endpoint

  /**
     * Process adding a subscriber to WP & Sendgrid
     *
     * @param WP_REST_Request $request
     * @return void|WP_Error
     */
    public function process_form(\WP_REST_Request $request) {

        $params = $request->get_params();
        $nonce = $params['_wpnonce'] ?? null;
        $email = $params['email'] ?? null;

        if(!wp_verify_nonce($nonce, 'nonce-sparkloop')) {
            return new WP_REST_Response(
                [
                    "nonce"  => $nonce,
                    "nonce_verify" => false
                ]
            );
        }

        if(!$email || false === filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return new WP_Error(
                'process_form', 'The email is not valid.'
            );
        }

       if(!$added = $this->add_subscriber($email)) {
            return new WP_Error(
                'process_form', 'Failed to add to our own list.'
            );
        }

        if('paused' !== $this->status) {
            $response_data = $this->add_email_to_sendgrid_list($email);
        }

        if(is_wp_error($response_data)) {
            return $response_data;
        }

        return rest_ensure_response(new \WP_REST_Response(
            [
                "successfully_added_subscriber" => $added,
            ]
        ));
    }

The value is the same as i see it correctly getting consoled out and it matches what gets generated in the input.

Leave a Comment