Create an API-based Chart

API-Based Chart How to make it secure?

It works fine with the code below, however everyone would have an ability to access this end point. What would you recommend so that only Forest Admin could access the end point?

Here is the code:

urls.py

from django.urls import path
from . import views
from django.views.decorators.csrf import csrf_exempt

urlpatterns = [
    path(
        "stats/total_amount", csrf_exempt(views.OrdersStatsTotalAmountAPIView.as_view())
    ),
]

views.py

class OrdersStatsTotalAmountAPIView(APIView):
    permission_classes = (AllowAny,)

    def post(self, *args, **kwargs):

        res = {
            "data": {
                "attributes": {
                    "value": {"countCurrent": get_all_orders_stats()["total_amount"]}
                },
                "type": "stats",
                "id": uuid.uuid4(),
            }
        }
        return Response(status=200, data=res)

Hey @Danil_Redko :wave:

So, you manage to fix this issue? (Since we’re not able to reproduce, we are still looking for more insights about this :))

Could you detail what is behind APIView ?

As you are creating an API Chart, the only way to ensure the request is allowed would be to check for the JWT authentication token. Here is an example

import uuid

from django_forest.utils.views.base import BaseView

from django.views import generic
from django.http import JsonResponse, HttpResponse

class OrdersStatsTotalAmountAPIView(BaseView):
    def post(self, request):
        if not self.is_authenticated(request):
            return HttpResponse(f'Unauthorized request', status=403)
        res = {
            "data": {
                "attributes": {
                    "value": {"countCurrent": 1}
                },
                "type": "stats",
                "id": uuid.uuid4(),
            }
        }
        return JsonResponse(status=200, data=res)

Let me know if that helps

Hey @jeffladiray,

Thank you for your approach, it DOES work. However, when I try to use rest_framework, it DOESN"T work.

In views.py:

APIView is a part of rest_framework.

from rest_framework.views import APIView
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response


class OrdersStatsTotalAmountAPIView(APIView):
    permission_classes = (IsAuthenticated,)

    def post(self, request):
        # if not self.request:
        #     return HttpResponse(f"Unauthorized request", status=403)
        res = {
            "data": {
                "attributes": {
                    "value": {"countCurrent": get_all_orders_stats()["total_amount"]}
                },
                "type": "stats",
                "id": uuid.uuid4(),
            }
        }
        return Response(status=200, data=res)

In settings.py

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "rest_framework_simplejwt.authentication.JWTAuthentication",
    ]
}

This approach doesn’t work. It throws this error:

{
  "detail": "Given token not valid for any token type",
  "code": "token_not_valid",
  "messages": [
    {
      "token_class": "AccessToken",
      "token_type": "access",
      "message": "Token is invalid or expired"
    }
  ]
}

My understanding of this issue is that isAuthenticated will look for request.user to be defined (Here)

In the case you describe, the forest admin JWT token most likely can’t be validated by rest_framework, as it was issue by django-forestadmin with your FOREST_AUTH_SECRET as the secret key.

However, the code I shared validates that all users that are authenticated on forestadmin can access the chart, and return an HTTP 403 otherwise - which is the best possible option for API-Chart.

Let me know if that helps :pray: