Quantcast
Channel: Active questions tagged rest - Stack Overflow
Viewing all articles
Browse latest Browse all 3672

Can Django identify first-party app access

$
0
0

I have a Django app that authenticates using allauth and, for anything REST related, dj-rest-auth.

I'm in the process of formalising an API

  • My Django app uses the API endpoints generally via javascript fetch commands. It authenticates with Django's authentication system (with allauth). It doesn't use dj-rest-auth for authentication, it uses the built in Django auth system.
  • My Discord bot uses the API as would be typical of a third-party app. It authenticates via dj-rest-auth, meaning it internally handles the refresh and session tokens as defined in dj-rest-auth's docs.

Currently the API is completely open, which means anyone could use cURL to access the endpoints, some of which an anonymous user can access. Others, require an authenticated user, and this is done with the request header data: Authorization: Bearer, as what dj-rest-auth takes care of (this is what my Discord bot uses).

I now want to expand on this by incorporating the Django Rest Framework API package so that API Keys are required to identify thirdparty client apps. For example, my Discord bot would use the Authorization: Api-Key header data to identify itself as an API client. It would be up to the thirdparties to make sure their API key doesn't get abused. The idea is that the API-Key is used as an extra authorisation layer such that different/extra access and throttles can be applied. My Discord bot, for example, would be granted more lenient throttling than say, a regular user who's applied for an API-Key.

Now my question...

API-Keys can be easily hidden in a bespoke Discord bot written in python because it's hidden from users of the bot, but what should I do for my regular/current Django app that uses the template system? If I use the HasAPIKey permission check for all endpoints as described in the Django Rest Framework API package, then my own Django app would be denied access.

I see two options

  • Either insert the Api-Key via middleware (and thus treating my Django app like any other client) or,
  • Adding a permission check to my DRF endpoints, e.g. IsUsingFirstPartyApp.

The problem is, I can only think of one way to identify "First party access" and that's via the HTTP_ORIGIN and HTTP_REFERER request header data.

I could have something like the following (code comments removed for brevity)...

class IsUsingFirstPartyApp(permissions.BasePermission):    def __init__(self):        self.ALLOWED_ORIGIN = getattr(settings, 'SITE_URL', None)        if not self.ALLOWED_ORIGIN:            raise ValueError("SITE_URL is not set in Django settings.")    def has_permission(self, request, view):        origin = request.META.get('HTTP_ORIGIN')        referer = request.META.get('HTTP_REFERER')        def is_valid_origin(header_value):            try:                parsed_origin = urlparse(header_value)                return f"{parsed_origin.scheme}://{parsed_origin.netloc}" == self.ALLOWED_ORIGIN            except ValueError:  # Catch specific parsing errors                return False        if origin:            return is_valid_origin(origin)        if referer:            return is_valid_origin(referer)        return False

For this, it's checking if the requests are being made from itself, e.g. from app.example.com.If I combine this with the HasAPIKey permission check (i.e. a logical OR) then my regular Django website can be used API-Key less as it always has. I can test this locally with cURL, where cURL gets an authentication error, but the anon-user using the website via a browser can access the endpoint just fine (via the javascript fetch request).

The only alternative I can think of is to move this same check to Django middleware and insert an API-Key into the request header. This would offer benefits for controlled throttling.

Or maybe what I'm doing is completely off the mark and not best practices. Am I on the right track, or is there a different way I should be doing this?


Viewing all articles
Browse latest Browse all 3672

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>