0

I currently have Django basic auth setup with Knox token authentication. Basic Auth doesn't seem sufficient for production work, so I want to replace that. Does Django have another password-based authentication_class that I can easily replace BasicAuthentication with, or is this a more involved process? If so, where do I start?

my login api view:

class UserLoginView(GenericAPIView):
  serializer_class = UserOrganizationSerializer
  authentication_classes = (BasicAuthentication,)
  permission_classes = (IsAuthenticated,)

  def post(self, request):
      """User login with username and password."""
      token = AuthToken.objects.create(request.user)
      return Response({
        'user': self.get_serializer(request.user).data,
        'token': token
      })

my default authentication classes:

REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [],
'DEFAULT_AUTHENTICATION_CLASSES': [
    'rest_framework.authentication.SessionAuthentication',
    'rest_framework.authentication.BasicAuthentication',
],
ambe5960
  • 1,870
  • 2
  • 19
  • 47
  • In your view you have `authentication_classes = (BasicAuthentication,)`. This means that DRF will ignore the list of default classes. If you want to enable the others, either remove that line from your view (prefereable), or add the other method to the list in sne same manner as BasicAuthentication. – Andrew Jul 10 '19 at 04:09
  • Also, you mention `knox` but you don't appear to be using it in your example. – Andrew Jul 10 '19 at 04:11

1 Answers1

0

One very common way is to use a JSON Web Token (JWT). The basic package is django-rest-framework-jwt. The instructions are pretty clear in the documentation, but here is an overview:

$> pip install djangorestframework-jwt

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        ...
    ),

Add the URL patterns

url_patterns = [ 
    path('jwt/', obtain_jwt_token, name='jwt'),
    ...
]

Get a token (using the excellent httpie utility)

http post localhost:8000/api/jwt/ username=u password=p
{
    "token": "REALLY-LONG-TOKEN"
}

Use that token to make a request:

http get localhost:8000/api/some-endpoint/ Authorization:"JWT REALLY-LONG_TOKEN"

Some Notes

  • JWT tokens are meant to be decodable by the client. They are protected by a signature, so they can't be modified
  • You can decode the token (online) and see the expiration time & other data
  • Tokens can be refreshed or verified through other urls provided by the package
  • Eventually refreshing will fail and the user will need to login again. This timespan is configurable (see my response to this other question)
Andrew
  • 8,322
  • 2
  • 47
  • 70
  • but you still have to use basic auth to login to obtain the token, correct? and (most) of the vulnerabilities would still be in play – ambe5960 Jul 10 '19 at 02:09
  • You don't need one to get the other, no. Its a separate login system, just like the Session auth (used for /admin/) is different. They do not depend on each other, but DRF supports using multiple at the same time. – Andrew Jul 10 '19 at 04:07