I have some requirements where I need to be able to authenticate the user either with username/password
or with an api_key
and return a JWT token for both cases.
My approach with the username/password:
if request.data['email'] and request.data['password']:
try:
user = User.objects.get(email=request.data['email'])
except User.DoesNotExist:
return Response({'Error': "Invalid username."}, status=status.HTTP_400_BAD_REQUEST)
if user:
if user.check_password(request.data['password']):
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
exp = datetime.now() + api_settings.JWT_EXPIRATION_DELTA
return Response({'token': token,
'exp': format(exp, 'U')},
status=status.HTTP_200_OK)
else:
return Response({'Error': "Invalid password."}, status=status.HTTP_400_BAD_REQUEST)
where jwt_payload_handler
is implemented as:
def jwt_payload_handler(user):
payload = {
"id": user.id,
"date": get_user_join_date(user),
"username": user.username, }
return payload
One of my questions is doesn't the keyword username need to be in the payload for the token to be a valid one?
What would a good approach be in the case of the api_key considering the key is not related to a user?
Should i create a default user that will be used in the payload given the api_key provided was correct?
Any suggestions?
Yes, you can create a default user to use with the API key. Of course, this will mean that data is shared across everyone who uses that API key, which may be fine in your usecase.
Beware that there are security gotchas for using just one API key. If the API key is compromised, you will need to send out a new key to every user of your API. Consider creating a separate API token for each consumer of your API, the same way that every consumer has their own username/password. That way, if a consumer compromises their API token, you only need to generate a new one for that particular consumer.