<p>Looks like you need to pass the csrf token through within your data as noted here <a href="https://craftcms.com/support/csrf-protection#updating-your-javascript" rel="nofollow noreferrer">https://craftcms.com/support/csrf-protection#updating-your-javascript</a></p>

CC BY-SA 3.0
2017-10-27T15:19:46.087Z
I tried this after seeing another post... but it didn't seem to work.
also, it seemed odd that the plugin has csrf included but their ajax snippet supplied doesnt have this. So I assumed they must have included this in the plugin itself?
https://github.com/craftcms/contact-form#ajax-form-submissions
ToddPadwick
CC BY-SA 3.0
2017-10-27T15:12:05.113Z
2017-10-27T15:12:05.113Z
hybrid_alex
<p>Your form action attribute should not be empty (<code>$('input[name="action"]', form).attr('action')</code>) and your AJAX request should be sent using POST (<code>$.post</code>).</p>

<pre><code>$.post('/', {
    dataType: 'json',
    action: $('input[name="action"]', form).attr('action'),
    data: $(this).serialize(),
    success: function(response) {
        if (response.success) {
            $('.request-ring-sizer .form-success').addClass("visible");
        } else {

            alert('An error occurred. Please try again.');
        }
    }
});
</code></pre>

CC BY-SA 3.0
2017-10-30T14:07:45.057Z
His action attribute is not empty and you don't need to use `$.post` instead of `$.ajax`, the way you described it sounds like `$.ajax` will not do the job but yours is just an alternative.
Robin Schambach
CC BY-SA 3.0
2017-10-31T13:39:51.397Z
To be more explicit, the default $.ajax method is GET (http://api.jquery.com/jquery.ajax/) and this plugin requires that data are send using POST (https://github.com/craftcms/contact-form/issues/102). If you want to use $.ajax instead of $.post you can, but you should specify the POST method parameter.
Romain P.
CC BY-SA 3.0
2017-10-30T13:18:13.337Z
2017-10-30T13:18:13.337Z
Romain P.
<p>Turns out this was a mistake in the README docs. </p>

<blockquote>
  <p>"The v1 README uses $.post, so this is only an issue when someone uses
  the v1 plugin and the v2 ajax instructions. I haven't tested it with
  v2, but it looks like the SendController requires POST too."</p>
</blockquote>

<p>The author of the plugin has now fixed this.</p>

<p><a href="https://github.com/craftcms/contact-form/issues/102" rel="nofollow noreferrer">https://github.com/craftcms/contact-form/issues/102</a></p>

CC BY-SA 3.0
2017-10-31T10:08:36.173Z
2017-10-31T10:08:36.173Z
ToddPadwick
<p>I am using the <a href="https://github.com/craftcms/contact-form/tree/v1" rel="nofollow noreferrer">Contact Form plugin</a> with AJAX. I have used the JS AJAX script supplied in the plugin but i get a 'Bad request: CSRF token could not be verified' error.
I have seen many other posts on here regarding AJAX and CSRF but non seem to apply to the Contact Form plugin. </p>

<p>Does anyone know how to get this to work?</p>

<pre><code>&lt;form method="POST" action="" accept-charset="UTF-8" class="request-ring-sizer"&gt;
    {{ getCsrfInput() }}
    &lt;input type="hidden" name="action" value="contactForm/sendMessage"&gt;
&lt;h2&gt;Order a free ring sizer&lt;/h2&gt;
&lt;div class="inputGroup"&gt;
        &lt;h3 class="small"&gt;Contact details&lt;/h3&gt;
        &lt;div class="inputWrap{% if message is defined and message.hasErrors('fromName') %} error{% endif %}"&gt;
            &lt;input onkeydown="active(this);" onblur="active(this); validate(this)" onfocus="active(this)" class="required" type="text" id="ring-sizer-fromName" name="fromName" value="{% if message is defined %}{{ message.fromName }}{% endif %}"&gt;
            &lt;span class="highlight"&gt;&lt;/span&gt;
            &lt;span class="bar"&gt;&lt;/span&gt;
            &lt;label for="ring-sizer-fromName"&gt;Your name&lt;/label&gt;
            &lt;span class="flash"&gt;{% if message is defined and message %}{{ message.getErrors('fromName') }}{% else %}Required{% endif %}&lt;/span&gt;
        &lt;/div&gt;
        &lt;div class="inputWrap{% if message is defined and message.hasErrors('fromEmail') %} error{% endif %}"&gt;
            &lt;input onkeydown="active(this);" onblur="active(this); validate(this)" onfocus="active(this)" class="required" type="email" id="ring-sizer-fromEmail" name="fromEmail" value="{% if message is defined %}{{ message.fromEmail }}{% endif %}"&gt;
            &lt;span class="highlight"&gt;&lt;/span&gt;
            &lt;span class="bar"&gt;&lt;/span&gt;
            &lt;label for="ring-sizer-fromEmail"&gt;Your email&lt;/label&gt;
            &lt;span class="flash"&gt;{% if message is defined and message %}{{ message.getErrors('fromEmail') }}{% else %}Required{% endif %}&lt;/span&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="inputGroup"&gt;
        &lt;h3 class="small"&gt;Your address&lt;/h3&gt;
        &lt;div class="inputWrap{% if message is defined and message.hasErrors('message[address1]') %} error{% endif %}"&gt;
            &lt;input onkeydown="active(this);" onblur="active(this); validate(this)" onfocus="active(this)" class="required" type="text" id="ring-sizer-message[address1]" name="message[address1]" value="{% if message is defined %}{{ message.message[address1] }}{% endif %}"&gt;
            &lt;span class="highlight"&gt;&lt;/span&gt;
            &lt;span class="bar"&gt;&lt;/span&gt;
            &lt;label for="ring-sizer-message[address1]"&gt;Address line 1&lt;/label&gt;
            &lt;span class="flash"&gt;{% if message is defined and message %}{{ message.getErrors('message[address1]') }}{% else %}Required{% endif %}&lt;/span&gt;
        &lt;/div&gt;
        &lt;div class="inputWrap"&gt;
            &lt;input onkeydown="active(this);" onblur="active(this); validate(this)" onfocus="active(this)" type="text" id="ring-sizer-message[address2]" name="message[address2]" value="{% if message is defined %}{{ message.message[address2] }}{% endif %}"&gt;
            &lt;span class="highlight"&gt;&lt;/span&gt;
            &lt;span class="bar"&gt;&lt;/span&gt;
            &lt;label for="ring-sizer-message[address2]"&gt;Address line 2&lt;/label&gt;
        &lt;/div&gt;
        &lt;div class="inputWrap{% if message is defined and message.hasErrors('message[city]') %} error{% endif %}"&gt;
            &lt;input onkeydown="active(this);" onblur="active(this); validate(this)" onfocus="active(this)" class="required" type="text" id="ring-sizer-message[city]" name="message[city]" value="{% if message is defined %}{{ message.message[city] }}{% endif %}"&gt;
            &lt;span class="highlight"&gt;&lt;/span&gt;
            &lt;span class="bar"&gt;&lt;/span&gt;
            &lt;label for="ring-sizer-message[city]"&gt;Town or City&lt;/label&gt;
            &lt;span class="flash"&gt;{% if message is defined and message %}{{ message.getErrors('message[city]') }}{% else %}Required{% endif %}&lt;/span&gt;
        &lt;/div&gt;
        &lt;div class="inputWrap short{% if message is defined and message.hasErrors('message[zipCode]') %} error{% endif %}"&gt;
            &lt;input onkeydown="active(this);" onblur="active(this); validate(this)" onfocus="active(this)" class="required" type="text" id="ring-sizer-message[zipCode]" name="message[zipCode]" value="{% if message is defined %}{{ message.message[zipCode] }}{% endif %}"&gt;
            &lt;span class="highlight"&gt;&lt;/span&gt;
            &lt;span class="bar"&gt;&lt;/span&gt;
            &lt;label for="ring-sizer-message[zipCode]"&gt;Post code&lt;/label&gt;
            &lt;span class="flash"&gt;{% if message is defined and message %}{{ message.getErrors('message[zipCode]') }}{% else %}Required{% endif %}&lt;/span&gt;
        &lt;/div&gt;
        &lt;div class="inputWrap{% if message is defined and message.hasErrors('message[countryId]') %} error{% endif %}"&gt;
            &lt;select onkeydown="active(this);" onblur="validate(this)" class="address-country" name="message[countryId]" class="required"&gt;
                &lt;option selected disabled&gt;Select a Country&lt;/option&gt;
                {% for key, option in countries %}
                    &lt;option value="{{ key }}"&gt;{{ option }}&lt;/option&gt;
                {% endfor %}
            &lt;/select&gt;
            &lt;span class="highlight"&gt;&lt;/span&gt;
            &lt;span class="bar"&gt;&lt;/span&gt;
            &lt;span class="flash"&gt;{% if message is defined and message %}{{ message.getErrors('message[countryId]') }}{% else %}Required{% endif %}&lt;/span&gt;
        &lt;/div&gt;
        &lt;div class="inputWrap"&gt;
            &lt;input onkeydown="active(this);" onblur="active(this); validate(this)" onfocus="active(this)" type="text" id="ring-sizer-message[state]" name="message[state]" value="{% if message is defined %}{{ message.message[state] }}{% endif %}"&gt;
            &lt;span class="highlight"&gt;&lt;/span&gt;
            &lt;span class="bar"&gt;&lt;/span&gt;
            &lt;label for="ring-sizer-message[state]"&gt;State&lt;/label&gt;
        &lt;/div&gt;
        &lt;input name="preferredJewellery" type="text" style="display:none;"&gt;
        &lt;input type="hidden" id="ring-sizer-subject" name="subject" value="I would like to request a free ring sizer"&gt;
        &lt;/div&gt;
    &lt;/div&gt;
    &lt;button type="submit" class="button button--primary button--primary--center page-fade"&gt;Submit&lt;/button&gt;
    &lt;div class="form-success"&gt;
        &lt;p class="center alert alert--success"&gt;Thank you. We will let you know when we've dispatched your free ring&amp;nbsp;sizer.&lt;/p&gt;
    &lt;/div&gt;&lt;!-- thanks --&gt;
&lt;/form&gt;






$(document).ready(function(){

    $('.request-ring-sizer').submit(function(ev) {
        console.log("ring sizer request submitted");
        // Prevent the form from actually submitting
        ev.preventDefault();

        // Send it to the server
        $.ajax('/', {
            dataType: 'json',
            data: $(this).serialize(),
            success: function(response) {
                if (response.success) {
                    $('.request-ring-sizer .form-success').addClass("visible");
                } else {

                    alert('An error occurred. Please try again.');
                }
            }
        });
    });
});
</code></pre>

CC BY-SA 3.0
2017-10-27T09:30:45.423Z
I you are using Craft 3, can you replace {{ getCsrfInput() }} with {{ csrfInput() }}? Alternatively, you could disable CSRF protection by adding 'enableCsrfProtection' => false in the craft/config/general.php config array (https://craftcms.com/support/csrf-protection).
Romain P.
CC BY-SA 3.0
2017-10-27T09:49:29.640Z
Craft 2. Didn't think Craft 3 was production ready yet.
also, for security purposes surely it wouldn't be good to remove CSRF protection?
ToddPadwick
CC BY-SA 3.0
2017-10-27T10:11:22.297Z
You're right, Craft 3 is not yet production ready. And you're right also, remove CSRF protection is not recommended. But 'enableCsrfProtection' => false could help you to make the form working until you find a real solution.
Romain P.
CC BY-SA 3.0
2017-10-27T11:00:53.560Z
It seems that the form send data using GET instead of POST. Could you change $.ajax to $.post?
Romain P.
CC BY-SA 3.0
2017-10-27T11:10:05.193Z
That makes sense... I have just updated that. however I now get a new error:
Uncaught TypeError: Cannot read property 'success' of undefined
ToddPadwick
<ajax><plugin-contactform><csrf>
Contact Form plugin - using Ajax, CSRF 400 bad request
# Contact Form plugin - using Ajax, CSRF 400 bad request

(Asked by: username_0 on 2017-10-27)

I am using the Contact Form plugin with AJAX. I have used the JS AJAX script supplied in the plugin but i get a 'Bad request: CSRF token could not be verified' error.
I have seen many other posts on here regarding AJAX and CSRF but non seem to apply to the Contact Form plugin. 
Does anyone know how to get this to work?

    {{ getCsrfInput() }}
    
Order a free ring sizer

        Contact details
        
            
            
            
            Your name
            {% if message is defined and message %}{{ message.getErrors('fromName') }}{% else %}Required{% endif %}
        
        
            
            
            
            Your email
            {% if message is defined and message %}{{ message.getErrors('fromEmail') }}{% else %}Required{% endif %}
        
    
    
        Your address
        
            
            
            
            Address line 1
            {% if message is defined and message %}{{ message.getErrors('message[address1]') }}{% else %}Required{% endif %}
        
        
            
            
            
            Address line 2
        
        
            
            
            
            Town or City
            {% if message is defined and message %}{{ message.getErrors('message[city]') }}{% else %}Required{% endif %}
        
        
            
            
            
            Post code
            {% if message is defined and message %}{{ message.getErrors('message[zipCode]') }}{% else %}Required{% endif %}
        
        
            
                Select a Country
                {% for key, option in countries %}
                    {{ option }}
                {% endfor %}
            
            
            
            {% if message is defined and message %}{{ message.getErrors('message[countryId]') }}{% else %}Required{% endif %}
        
        
            
            
            
            State
        
        
        
        
    
    Submit
    
        Thank you. We will let you know when we've dispatched your free ring sizer.
    







$(document).ready(function(){

    $('.request-ring-sizer').submit(function(ev) {
        console.log("ring sizer request submitted");
        // Prevent the form from actually submitting
        ev.preventDefault();

        // Send it to the server
        $.ajax('/', {
            dataType: 'json',
            data: $(this).serialize(),
            success: function(response) {
                if (response.success) {
                    $('.request-ring-sizer .form-success').addClass("visible");
                } else {

                    alert('An error occurred. Please try again.');
                }
            }
        });
    });
});

**Tags:** ajax, plugin-contactform, csrf

> **Comments:**
> **username_1**: I you are using Craft 3, can you replace {{ getCsrfInput() }} with {{ csrfInput() }}? Alternatively, you could disable CSRF protection by adding 'enableCsrfProtection' => false in the craft/config/general.php config array (https://craftcms.com/support/csrf-protection).  
> **username_0**: Craft 2. Didn't think Craft 3 was production ready yet. also, for security purposes surely it wouldn't be good to remove CSRF protection?  
> **username_1**: You're right, Craft 3 is not yet production ready. And you're right also, remove CSRF protection is not recommended. But 'enableCsrfProtection' => false could help you to make the form working until you find a real solution.  
> **username_1**: It seems that the form send data using GET instead of POST. Could you change $.ajax to $.post?  
> **username_0**: That makes sense... I have just updated that. however I now get a new error: Uncaught TypeError: Cannot read property 'success' of undefined  

---

## 3 answers

### Answer by username_2 on 2017-10-27. Score: 1

Looks like you need to pass the csrf token through within your data as noted here <https://craftcms.com/support/csrf-protection#updating-your-javascript>

> **Comments:**
> **username_0**: I tried this after seeing another post... but it didn't seem to work. also, it seemed odd that the plugin has csrf included but their ajax snippet supplied doesnt have this. So I assumed they must have included this in the plugin itself? https://github.com/craftcms/contact-form#ajax-form-submissions  

---

### Answer by username_1 on 2017-10-30. Score: 0

Your form action attribute should not be empty ($('input[name="action"]', form).attr('action')) and your AJAX request should be sent using POST ($.post).
$.post('/', {
    dataType: 'json',
    action: $('input[name="action"]', form).attr('action'),
    data: $(this).serialize(),
    success: function(response) {
        if (response.success) {
            $('.request-ring-sizer .form-success').addClass("visible");
        } else {

            alert('An error occurred. Please try again.');
        }
    }
});

> **Comments:**
> **username_3**: His action attribute is not empty and you don't need to use `$.post` instead of `$.ajax`, the way you described it sounds like `$.ajax` will not do the job but yours is just an alternative.  
> **username_1**: To be more explicit, the default $.ajax method is GET (http://api.jquery.com/jquery.ajax/) and this plugin requires that data are send using POST (https://github.com/craftcms/contact-form/issues/102). If you want to use $.ajax instead of $.post you can, but you should specify the POST method parameter.  

---

### Answer by username_0 on 2017-10-31. Score: 0

Turns out this was a mistake in the README docs.

> "The v1 README uses $.post, so this is only an issue when someone uses
> the v1 plugin and the v2 ajax instructions. I haven't tested it with
> v2, but it looks like the SendController requires POST too."

The author of the plugin has now fixed this.

<https://github.com/craftcms/contact-form/issues/102>


---

