Forums

OSError: write error then Forbidden (CSRF token missing or incorrect.): /accounts/login/

Hello !

I have an application running (www.batch.cooking) and one of my clients is complaining to get a CSRF error when trying to log in.

I had a look at the error log and it reads the following:

2021-05-07 13:44:42 Fri May 7 13:44:42 2021 - SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) on request /menu/ (ip 10.0.0.93) !!! 2021-05-07 13:44:42 Fri May 7 13:44:42 2021 - uwsgi_response_writev_headers_and_body_do(): Broken pipe [core/writer.c line 306] during GET /menu/ (10.0.0.93) 2021-05-07 13:44:42 ERROR 2021-05-07 13:44:42,305 user_wsgi_wrapper 4 140374436718464 OSError: write error 2021-05-07 13:45:39 WARNING 2021-05-07 13:45:39,671 log 4 140374436718464 Forbidden (CSRF token missing or incorrect.): /accounts/login/

Could you help me with that ?

Thanks a lot in advance :-) Lionel

How does your code serving that endpoint look like?

It looks like that:

def menu(request):
    if request.user.is_authenticated:
        try:
            request.session['address']
        except KeyError:
            try:
                request.session['address'] = str(UserAddress.objects.filter(user=request.user).first().id)
            except AttributeError:
                pass
    try:
        region = Region.objects.get(pk=request.session['region'])
    except KeyError:
        try:
            region = UserAddress.objects.filter(user=request.user).first().code.region
            request.session['region'] = str(region.id)
        except UserAddress.DoesNotExist:
            region = Region.objects.first()
            request.session['region'] = str(region.id)
        except (TypeError, AttributeError):
            region = Region.objects.first()
            request.session['region'] = str(region.id)
    meals = Meal.objects.filter(next_week=True, by__region=region.id)
    regions = Region.objects.all()
    try:
        addresses = UserAddress.objects.filter(user=request.user)
    except TypeError:
        addresses = None
    days = 4 - dt.datetime.now().weekday()
    def next_weekday(d, weekday):
        days_ahead = weekday - d.weekday()
        if days_ahead <= 0:  # Target day already happened this week
            days_ahead += 7
        return d + dt.timedelta(days_ahead)
    date = next_weekday(dt.datetime.now(), 0)
    context = {
        'meals': meals,
        'regions': regions,
        'addresses': addresses,
        'days': days,
        'date': date,
    }
    return render(request, 'menu/menu.html', context=context)

[edited by admin: formatting]

this is the login endpoint?

no that's the '/menu' endpoint which is provoking the disconnection (maybe some timeout issue), and then I guess that's why csrf fails on the '/login' endpoint... What do you think ?

How does the /login endpoint code look like?

It's the LoginView from all auth package, no modifications:

class LoginView( RedirectAuthenticatedUserMixin, AjaxCapableProcessFormViewMixin, FormView ): form_class = LoginForm template_name = "account/login." + app_settings.TEMPLATE_EXTENSION success_url = None redirect_field_name = "next"

@sensitive_post_parameters_m
def dispatch(self, request, *args, **kwargs):
    return super(LoginView, self).dispatch(request, *args, **kwargs)

def get_form_kwargs(self):
    kwargs = super(LoginView, self).get_form_kwargs()
    kwargs["request"] = self.request
    return kwargs

def get_form_class(self):
    return get_form_class(app_settings.FORMS, "login", self.form_class)

def form_valid(self, form):
    success_url = self.get_success_url()
    try:
        return form.login(self.request, redirect_url=success_url)
    except ImmediateHttpResponse as e:
        return e.response

def get_success_url(self):
    # Explicitly passed ?next= URL takes precedence
    ret = (
        get_next_redirect_url(self.request, self.redirect_field_name)
        or self.success_url
    )
    return ret

def get_context_data(self, **kwargs):
    ret = super(LoginView, self).get_context_data(**kwargs)
    signup_url = passthrough_next_redirect_url(
        self.request, reverse("account_signup"), self.redirect_field_name
    )
    redirect_field_value = get_request_param(self.request, self.redirect_field_name)
    site = get_current_site(self.request)

    ret.update(
        {
            "signup_url": signup_url,
            "site": site,
            "redirect_field_name": self.redirect_field_name,
            "redirect_field_value": redirect_field_value,
        }
    )
    return ret

login = LoginView.as_view()

Some configurations of browsers prevent some of the ways that CSRF tokens are handled in Django. If you only have one client that has the problem that might be it. Get them to try different browsers to check. Also, they may be starting out from a cached version of the page that did not have the CSRF token in it. Get them to refresh the starting page.

Ok thank you for your answer ! So your advice would be to not worry to much if it is pretty isolated ?

That depends entirely on you and the client. Whether to worry about that sort of thing depends on the value of the client to you vs the value of the time it takes to investigate.