I'm trying to set up an AWS Cognito backend I have a React frontend already working with it, now I need my DRF API to authenticate using the Cognito as backend.
I have found a few Python packages for that, none of them seem to be actively maintained django-warrant doesn't work with Django3 and is pretty much dead
Django Cognito JWT seems to be my best bet, but also not actively maintained, the documentation is very poor, and there is a medium post on how to use, not very detailed, but better than nothing.
So, I tried to follow the documentation
Added the env vars on my settings
COGNITO_AWS_REGION = 'us-east-1'
COGNITO_USER_POOL = 'us-east-1_xxxxxxx' # same user pool id I'm using on the React app
COGNITO_AUDIENCE = 'XXXXXXXXXXXXXXXXXXXXXX' # the same client id I'm using on the React app
Then on my DRF authentication classes:
'DEFAULT_AUTHENTICATION_CLASSES': [
'django_cognito_jwt.JSONWebTokenAuthentication',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
],
And finally the user model:
AUTH_USER_MODEL = 'accounts.MyUser'
COGNITO_USER_MODEL = "accounts.MyUser"
My custom User Model:
class MyUser(AbstractUser):
"""User model."""
username = None
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
I'm also using DRF JWT package, and if I try to login with a Cognito user, something like:
curl -X POST -H "Content-Type: application/json" -d '{"email":"[email protected]","password":"secretpassword"}' http://localhost/api-token-auth/
I get an error
{"non_field_errors":["Unable to log in with provided credentials."]}
On another hand, if I try to login with a local Django user via Django Rest Framework JWT it works fine and I get the JWT token as a response, so I guess the issue is the Cognito integration.
Any idea what I'm missing? or how can I debug in order to figure out what is happening?
UPDATE
After digging a bit more on the code, I found out a few things:
Even doing a DRF JWT authentication, the code end up at: django/contrib/auth/init.py Where it loops through all the authentication backends for Django, not for DRF:
for backend, backend_path in _get_backends(return_tuples=True):
Still using the ModelBackend
to authenticate the user.
So, I guess I also need to add some Cognito authentication backend for Django.
I checked if I could just use the same backend used on DRF, but then I got an error of invalid argument:
TypeError: authenticate() got an unexpected keyword argument 'email'
UPDATE 2 It seems that one of the issues is because I use email instead of username to authenticate, and none of the packages seems to support it
Basically, there are 2 steps to achieve your goal.
Authorization Bearer IdToken
to call API via curl
.Unlike rest_framework_jwt
, django_cognito_jwt
only deals with JWT token at header. django_cognito_jwt
does not cover step 1. That is why you are getting this error TypeError: authenticate() got an unexpected keyword argument 'email'
.
So, solution is use boto3 to get IdToken
and apply curl
by passing Authorization:Bearer IdToken
header.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With