Search code examples
pythondjangodjango-rest-frameworkapi-key

Why am I getting 403 for POST with DRF and rest_framework_api_key?


I am getting a 403 response from the server in my new Django app. It is very simple. I don't even have models, I just want to return an audio file, but I want to do it through an API. Because of that, since I am not going to have users, I need an API key, and I found that I can use the Django REST framework and the REST framework API key modules. I have followed the quickstarts and can't seem to get a response. It was working before, but it was authenticating through CSRF, and like I said, it is going to be an API, so I won't have CSRF cookies.

Here is the view I am using:

@api_view(["POST"])
def tts_view(request):
  data = request.POST

  voice_name = data.get("voice_name")
  text = data.get("text")

  if not voice_name or not text:
    return JsonResponse({"error": "Missing voice_name or text"}, status=400)

  return JsonResponse({"wav": text_to_wav(voice_name, text)}, status=200, safe=False)

The settings:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework_api_key',
    'TTS',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework_api_key.permissions.HasAPIKey",
    ]
}

And the fetch (the API key is just a test, so it doesn't matter):

fetch('/create-speech', {
    method: 'POST',
    body: JSON.stringify({
        voice_name: "es-US-Neural2-B",
        text: "Estoy feliz"
    }),
    headers: { 
        'Authorization': '0tSMNivu.f8DOBrHTTKfMQBGANNbjl5BJQcswN9ay',
        'Content-Type': 'application/json'
    }
})
.then((resp) => {
    if (!resp.ok) throw Error(`${resp.statusText} - ${resp.status}`);
    return resp.json();
})
.then((wav) => {
    console.log('success');
});

I am doing the fetch in the console on the default page, which is not defined (like I said, I only want an API).

I have tried including rest_framework.permissions.AllowAny into DEFAULT_PERMISSION_CLASSES, but it doesn't work either.

I don't really know what else to do, so any help would be appreciated. Thanks!


Solution

  • From the Django REST Framework API Key docs:

    By default, clients must pass their API key via the Authorization header. It must be formatted as follows:

    Authorization: Api-Key <API_KEY>

    You're missing the Api-Key part (notice the space between it and the <API_KEY> part). So your request should be:

    fetch('/create-speech', {
        ...
        headers: {
            'Authorization': 'Api-Key 0tSMNivu.f8DOBrHTTKfMQBGANNbjl5BJQcswN9ay',
            'Content-Type': 'application/json'
        }
    })
    ...