8.1 Authentication

Authentication is the mechanism of identifying/verifies a user during an incoming request.

Authentication gives us some advanced behavior like:

* Restriction on create, update or delete
* Unauthenticated requests should have read-only access.
* Adding throttling policies

8.1.1 Authentication vs Authorization

Authentication verifies a user is who they claim to be. or whether it anonymous or system user.

Authorization determines what an authenticated user is allowed to do/access.

First check Authentication/identification and then if the user is authenticated give some Permission/Authorization

8.1.2 How authentication is determined

FAQ: How is authentication handled in Django REST framework?

https://www.django-rest-framework.org/api-guide/authentication/#how-authentication-is-determined

The authentication schemes are always defined as a list of classes. REST framework will attempt to authenticate with each class in the list, and will set request.user and request.auth using the return value of the first class that successfully authenticates.

If no class authenticates, request.user will be set to an instance of django.contrib.auth.models.AnonymousUser, and request.auth will be set to None.

The value of request.user and request.auth for unauthenticated requests can be modified using the UNAUTHENTICATED_USER and UNAUTHENTICATED_TOKEN settings.

8.1.3 Setting the authentication scheme

The default authentication schemes may be set globally, using the DEFAULT_AUTHENTICATION_CLASSES setting. For example.

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ]
}

You can also set the authentication scheme on a per-view

# For - class based views
class ExampleView(APIView):
    authentication_classes = [SessionAuthentication, BasicAuthentication]
    pass

# For - function based view
@api_view(['GET'])
@authentication_classes([SessionAuthentication, BasicAuthentication])
def example_view(request, format=None):
    pass

8.2 Types of Authentication

  • TokenAuthentication
  • SessionAuthentication,
  • BasicAuthentication

8.2.1 BasicAuthentication

This authentication scheme uses HTTP Basic Authentication, signed against a user’s username and password. Basic authentication is generally only appropriate for testing.

If successfully authenticated, BasicAuthentication provides the following credentials.

  • request.user will be a Django User instance.
  • request.auth will be None.

Note: If you use BasicAuthentication in production you must ensure that your API is only available over https. You should also ensure that your API clients will always re-request the username and password at login, and will never store those details to persistent storage.

Enable BasicAuthentication - by adding below two classed in views

authentication_classes = (BasicAuthentication,)
permission_classes = [permissions.IsAuthenticatedOrReadOnly]

View CODE here: https://github.com/amrit94/drf-test/tree/09-BasicAuth

Code Difference: https://github.com/amrit94/drf-test/commit/98abb04e23f1a44befc67a28a04a2cd8dc52d067

Make API request using Postman

  • For every request pass username & password in Auth > Basic Auth
  • PATH: /users/
    • IsAuthenticated
    • Only Authenticated can make a request
  • PATH: /users/1/
    • IsAuthenticatedOrReadOnly
    • Anyone can read, Only Authenticated can update

8.2.2 SessionAuthentication

  • Work only for Browsable API login i.e works only on Borwser
  • The server will create a session for the user after the user logs in.
  • The session id is then stored on a cookie on the user’s browser.

Session authentication is appropriate for AJAX clients that are running in the same session context as your website.

  • csrf_token is used

Enable SessionAuthentication - by adding below two classed in views

# urls.py
path('api-auth/', include('rest_framework.urls'))

View CODE here: https://github.com/amrit94/drf-test/tree/10-SessionAuth

Code Difference: https://github.com/amrit94/drf-test/commit/18802916bf2ee8959874dc509e34335631e60165

Make API request using Browser - Incognito mode

  • Login PATH: /api-auth/login/
    • Use username and password to login
  • Logout PATH: /api-auth/logout/
    • Clear session
  • PATH: /albums/ and /albums/1/
    • Only Authenticated can update

Article:

8.2.3 TokenAuthentication

The token authentication works by exchanging username and password for a token that will be used in all subsequent requests so to identify the user on the server side.

Token authentication is suitable for client-server applications, where the token is safely stored. You should never expose your token, as it would be (sort of) equivalent of a handing out your username and password.

There are various 3rd party packages for Token authentication

8.3 Permissions

Authentication or identification by itself is not usually sufficient to gain access to information or code. For that, the entity requesting access must have authorization

Permissions are used to grant or deny access for different classes of users to different parts of the API.

If permission_class is used then and the request must pass all permission classes

Setting the permission policy

The default permission policy may be set globally, using the DEFAULT_PERMISSION_CLASSES setting. For example.

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticatedOrReadOnly',
    ]
}

If not specified, i.e. permission policy not set globally then this allows unrestricted access

# No need to set explictly
'DEFAULT_PERMISSION_CLASSES': [
   'rest_framework.permissions.AllowAny',
]

You can also set the permission policy on a per-view

# For - class based views
class ExampleView(APIView):
    permission_classes = [IsAuthenticated|ReadOnly]
    pass

# For - function based view
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def example_view(request, format=None)
    pass