CSRF verification failed. Request aborted. only for login page

Viewed 2728

I am creating a To-Do application as my first project in django. Everything works fine when I run on local server but when I deploy it to heroku, CSRF token is not working on login page only. The app is deployed here.

Issue: If we try any random or existing user on the login page, it shows CSRF verification failed BUT if we open /register endpoint i.e. Register a user on the app, it creates user and logs in to that user correctly at them time. Whole app features like adding a new task, editing a task, deleting a task works fine until I logout that user.

When I come back to the login page again, I am not able to login with any user account.

I've tried a lot of different methods like services in Procfile, environment variables for SECRET_KEY, providing meta tag in the main.html for csrf token using content={{ csrf_token }} but no luck.

Codes:

settings.py

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('SECRET_KEY')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.getenv('DEBUG', False)

ALLOWED_HOSTS = [
    '.herokuapp.com',
    '127.0.0.1:8000'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    #'django.middleware.csrf.CsrfViewMiddleware', Commented or not commented, it doesn't matter... issue still persists
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

views.py for login and register page

class CustomLoginView(LoginView):
    template_name = 'app/login.html'
    fields = '__all__'
    redirect_authenticated_user = True

    def get_success_url(self):
        return reverse_lazy('tasks')


class RegisterView(FormView):
    template_name = 'app/register.html'
    form_class = UserCreationForm
    success_url = reverse_lazy('login')

    def form_valid(self, form):
        user = form.save()
        if user is not None:
            login(self.request, user)
        return super(RegisterView, self).form_valid(form)

    def get(self, *args, **kwargs):
        if self.request.user.is_authenticated:
            return redirect('tasks')
        return super(RegisterView, self).get(*args, **kwargs)

main.html

<!DOCTYPE html>
{% load static %}
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      href="https://fonts.googleapis.com/css2?family=Nunito:wght@200&display=swap"
      rel="stylesheet"
    />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
    />

    <link
      rel="shortcut icon"
      href="https://raw.githubusercontent.com/HemantSachdeva/JokeApi/main/src/static/assets/favicon.ico"
    />

    <link rel="stylesheet" href="{% static 'style/main.css' %}">

    <title>To Do Tasks</title>
  </head>

  <body>
    <div class="container">{% block content %} {% endblock %}</div>
  </body>
</html>

login.html

{% extends 'app/main.html' %} {% block content %}

<div class="header-bar">
  <h1>Login</h1>
</div>

<div class="card-body">
  <form method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <input class="button" type="submit" value="Login" />
  </form>

  <p>Don't have an account? <a href="{% url 'register' %}">Register</a></p>
</div>

{% endblock content %}

register.html

{% extends 'app/main.html' %} {% block content %}

<div class="header-bar">
  <h1>Register</h1>
</div>

<div class="card-body">
  <form method="POST">
    {% csrf_token %}

    <label> {{ form.username.label }} <span style="color: red">*</span> </label>
    {{ form.username }}
    <ul>
      <li>150 characters or fewer.</li>
      <li>Letters, digits and @ - + _ . only.</li>
    </ul>

    <label> {{ form.password1.label }} </label>
    {{ form.password1 }} {{ form.password1.help_text }}

    <label> Confirm Password </label>
    {{ form.password2 }} <br />
    {{ form.password2.help_text }}

    <input
      style="margin-top: 10px"
      class="button"
      type="submit"
      value="Register"
    />
  </form>

  <p>Already have an account? <a href="{% url 'login' %}">Login</a></p>
</div>
{% endblock content %}

task.html (where it is supposed to land after successful login)

{% extends 'app/main.html' %} {% block content %}

<div class="header-bar">
  <div>
    <h1>Hello {{ request.user|capfirst }}</h1>
    <h3 style="margin: 0">
      You have <i>{{ count }}</i> incomplete task{{ count|pluralize:"s" }}.
    </h3>
  </div>
  {% if request.user.is_authenticated %}
  <a href="{% url 'logout' %}">Logout</a>
  {% endif %}
</div>

<div id="search-add-wrapper">
  <form method="GET" style="margin-top: 20px; display: flex">
    <input type="text" name="search" value="{{ search_input }}" />
    <input class="button" type="submit" value="Search" />
  </form>

  <a id="add-link" href="{% url 'task_new' %}">&#x2b;</a>
</div>

<div class="task-items-wrapper">
  {% for task in tasks %}

  <div class="task-wrapper">
    {% if task.complete %}

    <div class="task-title">
      <div class="task-complete-icon"></div>
      <i>
        <s> {{ task|capfirst }} </s>
      </i>
    </div>
    <p>
      <a href="{% url 'task_edit' task.id %}"
        ><i class="fa fa-edit" style="margin-right: 10px"></i
      ></a>

      <a class="delete-link" href="{% url 'task_delete' task.id %}">&#215;</a>
    </p>

    {% else %}

    <div class="task-title">
      <div class="task-incomplete-icon"></div>
      {{ task|capfirst }}
    </div>
    <p>
      <a href="{% url 'task_edit' task.id %}"
        ><i class="fa fa-edit" style="margin-right: 10px"></i
      ></a>

      <a class="delete-link" href="{% url 'task_delete' task.id %}">&#215;</a>
    </p>

    {% endif %}
  </div>

  {% empty %}
  <p>No task found.</p>
  {% endfor %}
</div>

{% endblock content %}

1 Answers

I never used DEBUG=True before posting this question and the error was clearly visible after using that.

Error:

Origin checking failed - https://hemant-to-do.herokuapp.com does not match any trusted origins.

Solution:

added following to settings.py

CSRF_TRUSTED_ORIGINS = [
    'https://hemant-to-do.herokuapp.com'
]
Related