Search code examples
pythondjangopython-cryptography

Expire token generator return InvalidToken


I'm trying to create a expire token generator. However when i for instance use generate_token and then use the token in get_token_value i keep getting cryptography.fernet.InvalidToken i guess this is a issue with the encoding in the two functions, but i'm not quite sure what im missing?

generator

from datetime import datetime, timedelta

import cryptography
from cryptography.fernet import Fernet
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.utils.encoding import force_bytes, force_text
class ExpiringTokenGenerator(object):
    FERNET_KEY = Fernet.generate_key()
    fernet = Fernet(FERNET_KEY)

    DATE_FORMAT = '%Y-%m-%d %H-%M-%S'
    EXPIRATION_DAYS = 1

    def _get_time(self):
        """Returns a string with the current UTC time"""
        return datetime.utcnow().strftime(self.DATE_FORMAT)

    def _parse_time(self, d):
        """Parses a string produced by _get_time and returns a datetime object"""
        return datetime.strptime(d, self.DATE_FORMAT)

    def generate_token(self, text):
        """Generates an encrypted token"""
        full_text = str(text) + '|' + self._get_time()
        token = self.fernet.encrypt(bytes(full_text, 'utf-8'))

        return token

    def get_token_value(self, token):
        """Gets a value from an encrypted token.
        Returns None if the token is invalid or has expired.
        """
        try:
            value = self.fernet.decrypt(bytes(token, 'utf-8'))
            separator_pos = value.rfind('|')

            text = value[: separator_pos]
            token_time = self._parse_time(value[separator_pos + 1: ])
            print(token_time)
            if token_time + timedelta(self.EXPIRATION_DAYS) < datetime.utcnow():
                return None

        except cryptography.fernet.InvalidToken:
            return None

        return text

    def is_valid_token(self, token):
        return self.get_token_value(token) != None


invoice_activation_token = ExpiringTokenGenerator()

Solution

  • What if you casted full_text as bytes first? Would that work?

    from datetime import datetime
    from cryptography.fernet import Fernet
    
    FERNET_KEY = Fernet.generate_key()
    fernet = Fernet(FERNET_KEY)
    get_time = datetime.utcnow().strftime('%Y-%m-%d %H-%M-%S')
    text = 'abc'
    full_text = bytes(str(text) + '|' + get_time, encoding='utf-8')
    token = fernet.encrypt(full_text)
    value = fernet.decrypt(token)
    
    print('Token:', token)
    print('Value:', value)
    

    Returns:

    Token: b'gAAAAABaIIPXtLrJ6YoJWUq9o9i5Q-1dCJ9Iae4mczFhHmW-UUQUKkgsPcm0MxzIJbBbIeziY3W-b2joT37kG-RxueEhwlx-x8n4B224thTWuebY1FfYXjI='
    Value: b'abc|2017-11-30 22-19-03'