Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do Django JSON Web Token Authentication without forcing the user to re-type their password?

My Django application uses the Rest Framework JWT for authentication. It works great and very elegant.

However, I have a use-case which I am struggling to build. I have already coded up a working solution for the "Forgot Password" workflow. I allow an un-authenticated user to reset their password if-and-only-if they click on a secret link that I send to their email address. However, I would like to modify this solution such that after the password-reset workflow is successfully completed, the user is automatically logged in without having to retype their username and (new) password. I would like to do this to make the user's experience as frictionless as possible.

The problem is I do not know how to make this work without having the user re-type their password (or storing it in clear-text in the DB which is obviously very bad). Below is the current way I get the JWT token. You can see that in line #12, I need the user's clear password. I don't have it. I only have the encrypted password stored in my_user.password.

How can I use the encrypted password in my_user.password instead of the clear password to obtain the JWT? If I cannot use it, then how is this workflow achieved using the Rest Framework JWT?

from rest_framework_jwt.views  import ObtainJSONWebToken
from rest_framework status
from django.contrib.auth.models import User

my_user = User.objects.get(pk=1)
ojwt = ObtainJSONWebToken()

if "_mutable" in dir(request.DATA):
    mutable = request.DATA._mutable
    request.DATA._mutable = True
request.DATA['username'] = my_user.username
request.DATA['password'] = "<my_user's clear password>"
if "_mutable" in dir(request.DATA):
    request.DATA._mutable = mutable


token_response = ojwt.post(request)
if status.is_success(token_response.status_code):
     # Tell the user login succeeded!!
else:
     # Tell the user login failed.
     # But hopefully, this shouldn't happen
like image 976
Saqib Ali Avatar asked Dec 17 '14 15:12

Saqib Ali


1 Answers

When working with Django REST Framework JWT, it is typically expected that the user is generating the token on their own. Because you are generating the token on behalf of the user, you can't use any of the standard views to make it work.

You are going to need to generate the token on your own, similar to how DRF JWT does it in the views. This means using something like the following for your view code

from rest_framework_jwt.settings import api_settings
from datetime import datetime


jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

my_user = User.objects.get(pk=1) # replace with your existing logic

payload = jwt_payload_handler(my_user)

# Include original issued at time for a brand new token,
# to allow token refresh
if api_settings.JWT_ALLOW_REFRESH:
    payload['orig_iat'] = timegm(
        datetime.utcnow().utctimetuple()
    )

return {
    'token': jwt_encode_handler(payload)
}

This should allow you to manually generate the token within the view, without having to know the user's password.

like image 192
Kevin Brown-Silva Avatar answered Sep 28 '22 11:09

Kevin Brown-Silva