flask-jwt
flask-jwt copied to clipboard
Refresh/Extend token life
Thoughts?
I also need this feature (maybe it's already there), actually we are using jwt for mobile app and it's not very convenient to login again after N days.
No thoughts on this yet. For the time being you can adjust the JWT_EXPIRATION_DELTA
+1
Currently exploring jwt-flask as part of a backend for a mobile application and also wonder what is the best practice for refreshing tokens...
How would you suggest to implement the refresh token? Should it be a second JWT with a long lifetime? The problem here is though, how do you invalidate the token if the user does not want to allow you further access?
Another option would be to let the user of the library deal with the verification of refresh tokens by having to specify a creation/verification function ..
+1
+1
Why refresh and not request a new one? What would be the point of expiration if all you do is extend it?
Requesting a new one forces the user to log in again.. Unless you implement a refresh token flow
+1
@patrickjahns i just have my other end of the api decrypt the token getting the expiration date and request a new one if its expired... is that sufficient?
That results in a huge security issue. An attacker can then intercept any token from your api and receive a valid new one by replaying previous tokens...
Your approach renders any expiration useless and you might as well set the expiration to several years, saving yourself the trouble of even checking.
Search around for jwt + refresh token for a secure approach to this issue. It would be nice if flask-jwt would provide the ability to easily implement that flow, but there needs to be some rewriting.
Also it feels that it is abandoned right now, since no pull requests are merged, neither are improvements comment nor is the pypy package updated. So for implementing the work flow of recommend writing your own small plugin inspired by flask-jwt On May 6, 2015 3:58 AM, "rlam3" [email protected] wrote:
@patrickjahns https://github.com/patrickjahns i just have my other end of the api decrypt the token getting the expiration date and request a new one if its expired... is that sufficient?
— Reply to this email directly or view it on GitHub https://github.com/mattupstate/flask-jwt/issues/29#issuecomment-99286543 .
I saw an implement here Blacklisting JSON Web Token API Keys
not sure you guys are talking about refresh before expiration or after expiration.
if refresh before expiration, we can do something like this, depending on the client to send the request.
from flask.ext.jwt import verify_jwt, current_user @app.route('/auth/refresh', methods=['get']) def refresh_token(): verify_jwt() payload = jwt.payload_callback(current_user) new_token = jwt.encode_callback(payload) return jwt.response_callback(new_token)
@s4turnight i think your code does not delete the old token so the old token can still be used.
Where exactly are the tokens anyways? How does this module know where to store them? Is there a way to return a list of tokens?
+1
For now I use Fresh-Token header in my API responses so client should not call /auth endpoint every time it's expired but on each response has new fresh token generated on backend.
So in this way I just set the token to expire in 3 minutes but if user is still active in the client-side application, it will receive fresh token in responses and have an experience of "continuous session".
And additionally you don't need to log-out user since the token's lifetime is too short. So if no any activity in 3 minutes, the token will be expired and the "session" will die.
And in such scenarios I would like to have some public method provided by the interface of the JWT instance to make able to just call jwt.generate_token() and easily get fresh token, maybe using the old one which is not expired yet.
What do you think about such stuff in the public interface?
Update.
For now I have to use a workaround to retrieve fresh token which looks like:
from flask import current_app
from flask_jwt import current_user
from flask_restful import Resource
def generate_token(user):
""" Currently this is workaround
since the latest version that already has this function
is not published on PyPI yet and we don't want
to install the package directly from GitHub.
See: https://github.com/mattupstate/flask-jwt/blob/9f4f3bc8dce9da5dd8a567dfada0854e0cf656ae/flask_jwt/__init__.py#L145
Hope it will be released on PyPI soon.
https://github.com/mattupstate/flask-jwt/issues/38#issuecomment-127167806
"""
jwt = current_app.extensions['jwt']
payload = jwt.payload_callback(user)
token = jwt.encode_callback(payload)
return token
class BaseResource(Resource):
def dispatch_request(self, *args, **kwargs):
response = super(BaseResource, self).dispatch_request(*args, **kwargs)
if current_user:
response[2]['Fresh-Token'] = generate_token(current_user)
return response
+1
+1
inspired by the answer from @f0t0n, but without using flask-restful.
I made a decorator that would require and reissue a new token, to be used anywhere I'd normally use @jwt_required()
def jwt_required_refresh(func):
@jwt_required()
def wrapper(*args, **kwargs):
token = jwt.jwt_encode_callback(current_identity)
resp = make_response(func(*args, **kwargs))
resp.headers['Fresh-Token'] = token
return resp
return wrapper
@mtourne In the absence of OAuth-style refresh token support, I like this approach but I'm unclear on how you would use it to decorate a handler. I guess the func arg in your decorator is the handler function? Could you add a (trivial) example?
Updated version :
def jwt_required_refresh(realm=None):
def wrapper(fn):
@wraps(fn)
@jwt_required(realm=realm)
def decorator(*args, **kwargs):
token = jwt.jwt_encode_callback(current_identity)
resp = make_response(fn(*args, **kwargs))
resp.headers['Fresh-Token'] = token
return resp
return decorator
return wrapper
Example:
@app.route("/api/v0/todo_list", methods=['GET'])
@jwt_required_refresh()
def get_todo_list():
pass
when using flask-jwt... should i need to send API Key every time too? or how does API key work with flask-jwt in this case?
+1
@mtourne Based on your example, when the token expires due to inactivity, how would you refresh the token? Thanks!
I would like to see this feature. It would be nice to have something built in where I could generate long lived refresh tokens (that only worked to get normal tokens, not to have access to the entire endpoints), and then use the short-lived normal tokens for consuming the api.
After reading stormpath's approach and several other publications it seems like the best way to refresh the JWT is to provide a "refresh_token" during authentication and every time a new "access_token" is given to client side.
# This should be the ideal way to provide the token
# authentication / refreshed token payload
{
"access_token": "....etc...",
"refresh_token": "...etc..."
}
The refresh_token can be used later to provide to server side to be consumed and provide a new "acess_token" again with a "newer refresh_token".
Would love some feedback on this approach. Thanks!
Reference: http://stackoverflow.com/questions/33645173/token-based-authentication-from-a-mobile-app https://grokswift.com/alamofire-OAuth2/ https://www.raywenderlich.com/99431/oauth-2-with-swift-tutorial https://stormpath.com/blog/build-note-taking-app-swift-ios
I've created a new flask-jwt extension which provides optional refresh tokens and optional revoking/blacklisting tokens baked in. It also has the idea of 'fresh' tokens, so when you first login you can access some critical views with your token (such as resetting a password), but subsequent tokens created with the refresh token wouldn't be able to access that view, until they re-authed and got a new 'fresh' token.
You can view it here: https://github.com/vimalloc/flask-jwt-extended/
@vimalloc Awesome man! Thanks I'll definitely be following your jwt-extended.
@rlam3 I haven't really implemented that part but in that example, you'd basically have the client check the token for expiration periodically and if the expiration time is close you'd hit the endpoint that triggers a token refresh.
Alternatively you could ask the user's input with some kind of "you're about to get logged out yes/no" ui dialogue, if you wanted to conditionally refresh the token.