jpadilla / django-rest-framework-jwt

JSON Web Token Authentication support for Django REST Framework
http://jpadilla.github.io/django-rest-framework-jwt/
MIT License
3.19k stars 648 forks source link

how to refresh existing tokens??? #474

Open cysnet opened 5 years ago

cysnet commented 5 years ago

image

i got an error message orig_iat field is required.

the settings is : REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication', ), }

cysnet commented 5 years ago

it is worked!!!! thanks a lot

SamsadSajid commented 5 years ago

How did you do it?

wnz27 commented 5 years ago

@SamsadSajid first,the orig_iag is the token created time,this issue means the token we send to server don't have this parameter. then we look the refresh source code, in rest_framework_jwt.serializers.py:

class RefreshJSONWebTokenSerializer(VerificationBaseSerializer):
     def validate(self, attrs):
         token = attrs['token']
         payload = self._check_payload(token=token)
        user = self._check_user(payload=payload)
        # Get and check 'orig_iat'
        orig_iat = payload.get('orig_iat')

        if orig_iat:
            # Verify expiration
            refresh_limit = api_settings.JWT_REFRESH_EXPIRATION_DELTA

            if isinstance(refresh_limit, timedelta):
                refresh_limit = (refresh_limit.days * 24 * 3600 +
                                 refresh_limit.seconds)

            expiration_timestamp = orig_iat + int(refresh_limit)
            now_timestamp = timegm(datetime.utcnow().utctimetuple())

            if now_timestamp > expiration_timestamp:
                msg = _('Refresh has expired.')
                raise serializers.ValidationError(msg)
        else:
            msg = _('orig_iat field is required.')
            raise serializers.ValidationError(msg)

        new_payload = jwt_payload_handler(user)
        new_payload['orig_iat'] = orig_iat

        return {
            'token': jwt_encode_handler(new_payload),
            'user': user
        }

that's very clear :

     if orig_iag:
           xxxxxxxxxxxxxxx  
     else:
            msg = _('orig_iat field is required.')
            raise serializers.ValidationError(msg)

so, we should fix it? because we through this method jwt_payload_handler to generate the jwt-token, we must look the source code:

def jwt_payload_handler(user):
    username_field = get_username_field()
    username = get_username(user)

    warnings.warn(
        'The following fields will be removed in the future: '
        '`email` and `user_id`. ',
        DeprecationWarning
    )

    payload = {
        'user_id': user.pk,
        'username': username,
        'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA
    }
    if hasattr(user, 'email'):
        payload['email'] = user.email
    if isinstance(user.pk, uuid.UUID):
        payload['user_id'] = str(user.pk)

    payload[username_field] = username

    # 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()
        )

    if api_settings.JWT_AUDIENCE is not None:
        payload['aud'] = api_settings.JWT_AUDIENCE

    if api_settings.JWT_ISSUER is not None:
        payload['iss'] = api_settings.JWT_ISSUER

    return payload

this if api_settings.JWT_ALLOW_REFRESH: it means if JWT_ALLOW_REFRESH exist then the handler to set the orig_iag, and the JWT_ALLOW_REFRESH default is False, so we add it to the our settings file and set it to True

ps: on the basis of RefreshJSONWebTokenSerializer, we can know the JWT_REFRESH_EXPIRATION_DELTA's value means in this time field you can refreash!

hope useful to you

seon54 commented 5 years ago

I've tested and found out that even though there is 'JWT_REFRESH_EXPIRATION_DELTA' on settins.py, it doesn't work. Only 'JWT_EXPIRATION_DELTA' works for refresh token.

wnz27 commented 5 years ago

I've tested and found out that even though there is 'JWT_REFRESH_EXPIRATION_DELTA' on settins.py, it doesn't work. Only 'JWT_EXPIRATION_DELTA' works for refresh token.

@seon54

Like I said above,the JWT_REFRESH_EXPIRATION_DELTA's value means in this time field you can refreash!
so you should set JWT_REFRESH_EXPIRATION_DELTA bigger than JWT_EXPIRATION_DELTA.

so base i understand, because i haven't research all django-jwt source code. so i think two situation:

when your jwt token expired: 1、the operation of refresh need you take a intiative to call. 2、the operation of refresh autocall

but i browse the django-jwt source code ,I don't seem find autocall about refresh. hope useful to u!

Matt-Texier commented 5 years ago

Hi Guys,

Just a comment and observation on my side about the same issue : for me, as soon as you set JWT_VERIFY_EXPIRATION to true, the decoder of the JWT is checking expiration of the token.

As such, even when running token refresh, the same decoding method is called and the program exits at this line of code :
payload = self._check_payload(token=token)

If you look at this line of code: https://github.com/GetBlimp/django-rest-framework-jwt/blob/0a0bd402ec21fd6b9a5f715d114411836fbb2923/rest_framework_jwt/utils.py#L101

You see that expiration is always tested during decoding once set in settings of Django. Even when asking for a refresh ...

For me, in case of refresh it should not check expiration time of the token but rather check JWT_REFRESH_EXPIRATION_DELTA.

So I wonder if we are not facing a bug here ... but I am not 100% sure.

What do you think ?