Prequisites
- A React Native project
- A Django project
Which authentication method should you use?
Every application is different, in general DRF states that SessionAuthentication
should be used if the client is running in the same session context as your website. However, for mobile applications, TokenAuthentication
is a better option for applications.
Once the user logs in, the server generates a token that the client stores securely. For every request to the backend, the client sends this token in the Authorization header. It’s stateless and works well for APIs, but you’ll need to handle token expiration and refresh mechanisms. Therefore, this is what we’re going to use.
Installing Django REST framework
First of all we need to install DRF, which can be done by running:
pip install djangorestframework
Remember that this should be run within your Python environment, in which case you may need to run source venv/bin/activate
first. We also need to update our settings.py
by adding:
INSTALLED_APPS = [
...
'rest_framework',
'rest_framework.authtoken',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
We’re setting the both the default authentication class and permission classes, since we want each request that is sent to the server to be authenticated, with the exception for the login view.
Creating a LoginView
Now that we have the basics set up, we need to create a new LoginView
. For this, we’ll be using a DRF GenericAPIView.
from django.contrib.auth import authenticate, login
from rest_framework import status
from rest_framework.authtoken.models import Token
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from account.serializers import LoginUserSerializer
class LoginView(GenericAPIView):
serializer_class = LoginUserSerializer
# We need to ensure that the default permission classes are not used
authentication_classes = []
permission_classes = []
def post(self, request, *args, **kwargs):
data = request.data
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
authenticated_user = authenticate(
email=data['email'],
password=data['password'],
)
if not authenticated_user:
return Response(status=401)
login(request, authenticated_user)
token, _ = Token.objects.get_or_create(user=authenticated_user)
return Response(
status=200,
data={
**serializer.data,
'token': token.key,
},
)
The LoginUserSerializer
in this case is just a simple serializer for what the request data should contain:
from rest_framework import serializers
class LoginUserSerializer(serializers.Serializer):
email = serializers.EmailField(required=True)
password = serializers.CharField(write_only=True, required=True)
Now we’ve got everything set for logging in and getting a token.
Setting up React Native for success
I’m going to skip the frontend parts of this and focus on the few functions of importance.
To ensure that every request contains the header Authorization
with the token, one way to make it simple is to modify the axios
interceptors.
I’d suggest creating a new file, which you import every time you need to request anything from the backend.
Mine looks like this:
import axios, { AxiosInstance,InternalAxiosRequestConfig } from 'axios'
import { store } from '../store'
const ensureToken = (config: InternalAxiosRequestConfig) => {
const state = store.getState()
config.headers['Authorization'] = `Token ${state.user?.user?.token}`
return config
}
const addInterceptors = (instance: AxiosInstance) => {
instance.interceptors.request.use(ensureToken)
return instance
}
const api = axios.create({
baseURL: process.env.EXPO_PUBLIC_BASE_API_URL,
})
export default addInterceptors(api)
With this setup, the file can be imported whenever a backend request is required.
Wrap-up
By following this guide, you’ve established a solid foundation for integrating token-based authentication in your Django and React Native application. Here’s what you’ve achieved:
-
Selected an Authentication Method: You chose TokenAuthentication as the ideal approach for mobile applications due to its stateless nature and compatibility with APIs.
-
Configured Django REST Framework: You installed DRF and set up authentication and permissions in settings.py to secure your API endpoints effectively.
-
Created a Login API: You implemented a LoginView using DRF’s GenericAPIView and crafted a simple serializer to handle user login and token generation.
-
Enhanced the React Native Client: By setting up an Axios instance with interceptors, you ensured that every request from the client includes the user’s authentication token seamlessly.
With these components in place, your application is ready to securely handle user authentication and API interactions. Remember to implement additional features such as token expiration handling and refresh mechanisms to further enhance security and user experience. Happy coding!