2

Django-Rest-Knox provides a view to give you the token to authenticate, but that view requires authentication:

https://github.com/James1345/django-rest-knox/blob/05f218f1922999d1be76753076cf8af78f134e02/knox/views.py#L16

How is this intended to be used?

Following the documentation on setting it up, my settings look like this:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ('knox.auth.TokenAuthentication',),
}

I tried authenticating this way:

fetch("http://localhost:8000/api-v1/auth/login/", {
    method: "POST",
    body: JSON.stringify({email: email, password: password}),
    headers: {
        "Accept": "application/json",
        "Content-Type": "application/json",
    }
}).then(result => result.json())
    .then(result => {
        console.log(result);
    });

but IsAuthenticated is stopping me and showing this message:

Unauthorized: /api-v1/auth/login/

on the Django side, and this on the JavaScript side:

{"detail":"Authentication credentials were not provided."}

Email and password are the same I'm using to log in successfully on the admin tool.

Just for clarification, I don't have a system where someone logs in to a web application and copies and pastes a token to some other application. In the system I'm building, you log in directly through the API with your user and password, then the token is obtained and saved for subsequent requests.

Very similar to how LastPass works, that the first time you open it, it asks you for an email and password (not to go away and fetch a token from a web site):

enter image description here

The whole objective of Knox's LoginView is to generate and provide that token in an API request: https://github.com/James1345/django-rest-knox/blob/05f218f1922999d1be76753076cf8af78f134e02/knox/views.py#L30-L55

This is also how pretty much every mobile app as well as SPAs work, in which they ask you for a user/email and password to obtain the token, and then save the token for further requests.

Pablo Fernandez
  • 279,434
  • 135
  • 377
  • 622
  • you get authenticated to the view by using the credentials of the account of the user. Then user gets a token which then can be used to make authorised API calls to the app – Nikos M. May 06 '19 at 08:46
  • @NikosM. how do you provide provide the credentials? – Pablo Fernandez May 06 '19 at 08:50
  • @NikosM. yeah, of course :) I have created the user, I can log in just fine in the admin tool, now I'm trying to log in to use the API. – Pablo Fernandez May 06 '19 at 08:53
  • @NikosM. I want the user to log in to the app entering email and password (like you do in pretty much any mobile and single page app out there), not having to obtain a token, having to copy it, etc. Also, once you have the token, what's the point of this view (which purpose is to give you a token). – Pablo Fernandez May 06 '19 at 08:57
  • Does this answer your question? [How to authorize django-rest-knox login path without 401 error?](https://stackoverflow.com/questions/53828599/how-to-authorize-django-rest-knox-login-path-without-401-error) – SEDaradji May 30 '20 at 06:17

3 Answers3

3

Follow this guide. And you will have to split the serializer data to get the token.

https://gist.github.com/AndrewPix/cdd9276b1d5683459b965d5cc4517b26

For example, your result would be this after login:

"(<AuthToken: 853d34ff808bf07c112b87bbc1bf59e3159fa6765f8bcd34b6376fbef08c9369e2b28a39ff868949e047de4a2164183cc1b16d61e87476129c18339dedee6ff0 : mdmd@gmail.com>, '326fe653946b99978900ae3820cb71f5eecf613ca71f8acde4e001a938bbba48')" 

This is your token:

326fe653946b99978900ae3820cb71f5eecf613ca71f8acde4e001a938bbba48

Don't know why the author made it tough to get the token. You just have to parse through the string.

Anyone with a better solution should kindly submit an answer.

bobozar
  • 47
  • 6
0

You have to choose your authentication method on the login view. So the first time you have to authenticate via one of the available authentication method in Django.

Basic Auth is a good candidate for that.

from knox.views import LoginView as KnoxLoginView
from rest_framework.authentication import BasicAuthentication
from rest_framework.permissions import IsAuthenticated


class LoginAPI(KnoxLoginView):
    authentication_classes = [BasicAuthentication]
    permission_classes = [IsAuthenticated]

And then on the front-end:

const credentials = btoa(`${username}:${password}`);

fetch("http://localhost:8000/api-v1/auth/login/", {
   method: "POST",
   body: JSON.stringify({}),
   headers: {
        "Accept": "application/json",
        "Content-Type": "application/json",
        "Authorization": `Basic ${credentials}`
    }
}).then(result => console.log(result));
loicgasser
  • 1,403
  • 12
  • 17
0

I had experienced the problem at url api/login, in my case the problem was at views.py

class LoginAPI(KnoxLoginView):
    permission_classes = (permissions.AllowAny)

I didn't put the comma after permissions.AllowAny, corrected code->

class LoginAPI(KnoxLoginView):
    permission_classes = (permissions.AllowAny,)