question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Multiple authentication backends with conditional csrf

See original GitHub issue

Obviously cookie based auth needs the csrf, but how can I exclude the csrf for authorization header based auth? This is my configuration:

router = NinjaAPI(auth=(AuthBearer(), django_auth), csrf=True)

So the point is, the csrf check needs to be based on the authentication backend that is in use. Now it is always enforced. (django-rest-framework does that correctly)

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:8
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

3reactions
shughes-ukcommented, Feb 19, 2022

Thank you @Photonios for this but i’ve spotted an issue

class ExemptAPIKeyAuthFromCSRFMiddleware:

The view_func instances seem to be reused between multiple requests, so by setting csrf_exempt you’re disabling CSRF checks for all future requests.

You could toggle it back to False on a per request basis, but I think that might run into race conditions when you have django serving requests in a concurrent fashion (async/gevent).

The CSRF middleware checks request._dont_enforce_csrf_check and will exit early if set https://github.com/django/django/blob/fac3dd7f390d372736e05974cc5c3ef1a3768fbb/django/middleware/csrf.py#L433-L438

We can use this to ‘trick’ it into thinking CSRF has already been checked just for specific requests. The modified version looks like this

class ExemptAPIKeyAuthFromCSRFMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        return self.get_response(request)

    def process_view(self, request, view_func, view_args, view_kwargs):
        if request.user.is_authenticated:
            return
        klass = getattr(view_func, "__self__", None)
        if not klass:
            return
        if isinstance(klass, PathView):
            request._dont_enforce_csrf_checks = True

Definitely need a mechanism to avoid having to do these hacks, API’s that deal with browser based auth and some other auth where CSRF is not required seem to be fairly common.

2reactions
Photonioscommented, Dec 17, 2021

you can set global csrf=False

and then extend django_auth and add csrf check inside your own authenticator

You can’t really do the CSRF check in the authenticator since you do not have access to the view function. I ended up solving this with a custom middleware that exempts views from CSRF if non-session authentication is used.

I’d be highly in favour of being able to control which authentication methods require CSRF and which don’t natively in Django Ninja.

from ninja.operation import PathView


class ExemptAPIKeyAuthFromCSRFMiddleware:
    """Exempts API views from CSRF if not authenticated with
    Django session authentication.

    This allows API calls with an API  key to pass without
    having to pass a CSRF token."""

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        return self.get_response(request)

    def process_view(self, request, view_func, view_args, view_kwargs):
        if request.user.is_authenticated: # this check might not be enough if your other auth methods set `request.user`.
            return

        klass = getattr(view_func, '__self__', None)
        if not klass:
            return

        if not isinstance(klass, PathView):
            return

        for operation in klass.operations:
            setattr(operation.view_func, 'csrf_exempt', True)
Read more comments on GitHub >

github_iconTop Results From Across the Web

How to deal with two websites with one backend CSRF ...
CORS works by requiring the server to include a specific set of headers that allow a browser to determine if and when cross-domain...
Read more >
Cross-Site Request Forgery Prevention Cheat Sheet
CSRF tokens prevent CSRF because without a token, an attacker cannot create valid requests to the backend server. For the Synchronised Token Pattern,...
Read more >
Is a backend API server vulnerable to CSRF?
Authentication credentials are automatically sent with cross-origin requests when basic authentication is used or cookies - although many modern ...
Read more >
CSRF Protection - Laravel - The PHP Framework For Web ...
When these two tokens match, we know that the authenticated user is the one ... If you are building a SPA that is...
Read more >
The CSRF Protection with Spring Security - YouTube
The CSRF Protection with Spring Security | Spring Boot Backend #3.5. Watch later. Share. Copy link. Info. Shopping. Tap to unmute. If ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found