Django Rest Framework JWT: How to change the token expiration time when logged in

JWT token refresh is a little confusing, and i hope this explanation helps.

  • tokens have an issued at time (iat in the token)
  • tokens have an expiration date (now() + 1 hour, for example)
  • the token can't be changed. server can only issue a new one
  • iat never changes, but expires does change with each refresh

When you want to extend a token, this is what happens:

  • You send your token to the server endpoint /.../refresh/
  • Server checks its not expired: now() <= token.iat + JWT_REFRESH_EXPIRATION_DELTA
  • If not expired:
    • Issue a NEW token (returned in the json body, same as login)
    • New Token is valid for now() + JWT_EXPIRATION_DELTA
    • The issued at value in the token does not change
    • App now has 2 tokens (technically).
    • App discards the old token and starts sending the new one
  • If expired: return error message and 400 status

Example

You have EXPIRATION=1 hour, and a REFRESH_DELTA=2 days. When you login you get a token that says "created-at: Jun-02-6pm". You can refresh this token (or any created from it by refreshing) for 2 days. This means, for this login, the longest you can use a token without re-logging-in, is 2 days and 1 hour. You could refresh it every 1 second, but after 2 days exactly the server would stop allowing the refresh, leaving you with a final token valid for 1 hour. (head hurts).

Settings

You have to enable this feature in the backend in the JWT_AUTH settings in your django settings file. I believe that it is off by default. Here are the settings I use:

JWT_AUTH = {
    # how long the original token is valid for
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=2),

    # allow refreshing of tokens
    'JWT_ALLOW_REFRESH': True,

    # this is the maximum time AFTER the token was issued that
    # it can be refreshed.  exprired tokens can't be refreshed.
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
}

Then you can call the JWT refresh view, passing in your token in the body (as json) and getting back a new token. Details are in the docs at http://getblimp.github.io/django-rest-framework-jwt/#refresh-token

$ http post localhost:8000/auth/jwt/refresh/ --json token=$TOKEN

Which returns:

HTTP 200 
{
    "token": "new jwt token value" 
}