How to forcefully expire token after using it (before expiry time set for the token using itsdangerous library in python)
Asked Answered
P

2

7

My use case is to generate token for reset password api. Which I am doing with itsdangerous library in python. https://pythonhosted.org/itsdangerous/.

This token(within reset password link) is forwarder through email to client, the token has expiry time limit which is validated and after that password reset can go through successfully.

Issue here is that once password reset is successful how do I make sure the same token(email link) cannot be used again within the expiry time limit. I can see itsdangerous has URLSafeTimedSerializer which helps evaluate during the validation phase on how old the token is. On the other hand TimedJSONWebSignatureSerializer helps set the expiry time while generating token. Please check the attached piece of code.

Is there a better way to expire token forcefully? If not what would be the best way to save the state of token that it has been used?

import itsdangerous

key = "test"

# signer = itsdangerous.URLSafeTimedSerializer(key)
signer = itsdangerous.TimedJSONWebSignatureSerializer(key, expires_in=5)
email = "[email protected]"

# token = email  # to be used with URLSafeTimedSerializer
token = signer.dumps({"email": email})

print token

# print signer.loads(token, max_age=5) # to be used with URLSafeTimedSerializer
print str(signer.loads(token)["email"]) # to be used with TimedJSONWebSignatureSerializer
Pinnacle answered 16/5, 2019 at 13:31 Comment(0)
O
3

Once your token is generated and signed it remains valid until it expires. You cannot change that anymore. With that in mind, it also means that you cannot change any of its payload once it was signed, otherwise it will be rendered invalid (due to an invalid signature).

One thing you could do however is to generate an unique key ("some_key") once you generate your token and store the key in your database. In the end, the tokens payload which will be issued to the user could look like this: {"email": email, "reset_key": "some_key"}.

Each time someone would try to reset his password, you would simply verify that key first in order to allow or reject a request.

Once the reset was successfull you would simply remove that key from your database (or flag it as invalid). That would make the following requests containing the same token invalid, even though the token itself is still valid from an expiry perspective.

I hope that helps!

Oaf answered 16/5, 2019 at 13:59 Comment(0)
E
1

I realise this is a late answer, so added for the benefit of others finding this question.

Another approach might be to use a boolean session variable such as tokenused and set this to True once the token has been de-serialised; thus invalidating the use of the token.

For example, using the session object in Flask:

    uid = {}
    try:
        if not session['tokenused']:
            session['tokenused'] = True
            s = Serializer(app.config['SECRET_KEY'])
            uid = s.loads(token)
    except Exception as err:
        errors.internal_server_error(err)
    return uid
Endometrium answered 2/8, 2020 at 21:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.