I am trying to implement Auth0 JWT-based authentication in my Django REST API using the django-rest-framework. I know that there is a JWT library available for the REST framework, and I have tried using it because the official Auth0 twitter account mentioned that it should work well with auth0 + Django.
EDIT: I am using the official auth0 python api guide for this code. It's written for flask, but I figured I could just port it to Django seeing as they work similarly.
Now, that didn't work out how I wanted to, so I am trying to write my own login_required
decorater for a view. The code I have here is as following:
def auth_required(f):
def wrap(request, *args, **kwargs):
auth = request.META.get('HTTP_AUTHORIZATION', None)
if not auth:
return authenticate({'code': 'authorization_header_missing', 'description': 'Authorization header is expected'})
parts = auth.split()
if parts[0].lower() != 'bearer':
return authenticate({'code': 'invalid_header', 'description': 'Authorization header must start with Bearer'})
elif len(parts) == 1:
return authenticate({'code': 'invalid_header', 'description': 'Token not found'})
elif len(parts) > 2:
return authenticate({'code': 'invalid_header', 'description': 'Authorization header must be Bearer + \s + token'})
token = parts[1]
try:
payload = jwt.decode(
token,
base64.b64decode(SECRET.replace("_","/").replace("-","+")),
audience=CLIENT_ID,
)
except jwt.ExpiredSignature:
return authenticate({'code': 'token_expired', 'description': 'token is expired'})
except jwt.InvalidAudienceError:
return authenticate({'code': 'invalid_audience', 'description': 'incorrect audience, expected: ' + CLIENT_ID})
except jwt.DecodeError:
return authenticate({'code': 'token_invalid_signature', 'description': 'token signature is invalid'})
return f(request, *args, **kwargs)
wrap.__doc__=f.__doc__
wrap.__name__=f.__name__
return wrap
Now, the authenticate()
is basically my custom implementation for Jsonify()
which is used in the documentation of Auth0 for Python API's. I have verified that this works, so that's not a problem.
SECRET
is my Auth0 secret, encoded in base64 (any other keys failed to decode)
CLIENT_ID
is my Auth0 client ID which is used as the audience, according to the Auth0 documentation.
I am using the Angular seed project on the frontend-side, and I have verified that the token indeed gets sent with the request, and I have verified that it's the exact same token that gets stored in the token
variable on the backend.
When jwt.decode()
is called, it will trigger the jwt.DecodeError
every time, and I have been spending countless hours trying to fix this, but I am absolutely stunned as to why this is not working. I have tried setting the JWT options to false, specifically the verify signature one. This worked, but I assume that it's unsafe to disable the verifying of the JWT signature.
I cannot figure out why this is failing me, I have tried this same code without it being in a decorator and it does the same thing. The view which is decorated is just an empty view which returns an OK HttpResponse.
Tldr; Using Django-REST + Auth0 JWT -- jwt.decode()
will not work no matter what I do.
EDIT2: It's worth mentioning I am corsheaders
for django-rest which allows me to make cross-domain requests. I have also followed the tip at the bottom of the Python API guide from Auth0 to uninstall and reinstall the JWT library, but this did nothing for me.
Am I overlooking something, is this implementation plain unsecure or do you have any better way to implement Auth0 with Django? Please let me know, this problem is causing me nightmares.