I have a frontend login form that sends a request to Craft's own actions/users/login action. I've used this same process in another project and it works there, but not here, and I can't figure out what might be different.

After entering username and password to my form and submitting it, I get the 400 Bad Request error page with "Unable to verify your data submission." When I look at the login request in the browser's network tab I can see it has a CSRF value.

One of the weirdest things about this is that sometimes I can click the "back" button and voila, I will be logged in! I haven't been able to tell what's different when I sometimes get a 200 status and other times where I get a "cancelled" status. No matter what the status is, I always get that "Unable to verify your data submission" error page.

Here is my frontend login method:

login() {
  if (!this.loginName || !this.password) {
    this.error = "Enter a username and/or password";


  const config = {
    headers: {
      'content-type': 'application/x-www-form-urlencoded;charset=utf-8'

  const data = qs.stringify({
    loginName:  this.loginName,
    password:   this.password,
    rememberMe: this.rememberMe

    .post("/actions/users/login", data, config)
    .then(response => {
      if (response.data.errorCode === "invalid_credentials") {
        this.loggingIn = false;
        this.error = response.data.error;


      if (response.data.success) {

My axios utility:

import axios from 'axios';

export default axios.create({
  headers: {
    'X-CSRF-TOKEN': window.csrfTokenValue

And how I am attaching CSRF stuff to the window in my main template:

    window.timezone = "{{ craft.app.timezone }}";
    window.csrfTokenName = "{{ craft.app.config.general.csrfTokenName|e('js') }}";
    window.csrfTokenValue = "{{ craft.app.request.csrfToken|e('js') }}";

I'm at my wit's end with this and am unable to figure out how to troubleshoot this further...

  • 1
    Do you need to qs.stringify your data? Seems like Axios knows how to manage an object as POST data… I'd also consider setting the X-Requested-With header, and a proper Accepts header! – August Miller Feb 10 '20 at 4:26
  • I think the data needs to be stringified, but I'm not 100% sure I guess. Interestingly when I make the request without using stringify I get a 400 status as a response. Every other time--except when it randomly gives me the error AND a 200 status--I get Cancelled. Adding 'X-Requested-With': 'XMLHttpRequest' and 'Accept': 'application/json' to my headers object doesn't change the behavior at all :( – Steven Thate Feb 10 '20 at 11:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.