pallets-eco / flask-jwt Goto Github PK
View Code? Open in Web Editor NEWJWT (JSON Web Tokens) for Flask applications
License: MIT License
JWT (JSON Web Tokens) for Flask applications
License: MIT License
Hi guys,
I need to authenticate my users in Active Directory before they can use my REST API.
After beeing authenticated, I need to pass them the jwt.
Is it possible to do it using Flask-jwt?
It not, any ideias how I can implement that?
Thx!
There are currently two different ways to specify handlers:
JWT_ENCODE_HANDLER
, JWT_DECODE_HANDLER
, JWT_PAYLOAD_HANDLER
JWT#user_handler
, JWT#error_handler
Why not just have one mechanism for defining these handlers? Personally, the decorator syntax feels most natural:
@jwt.payload_handler
def make_payload(user):
return {'user_id': user.id }
@jwt.user_handler
def get_user(payload):
return User.get(payload['user_id']
This makes for a more consistent and cohesive API.
Why use PyJWT instead of itsdangerous, which has an implementation of JWS?
It appears there something like current_user from flask_login, sadly it doesn't appear to be documented. Could you add documentation on that?
Also, user_handler is not sufficiently documented, I think. Why do I need it if I already have the auth handler?
I've switched over all of my auth mechanisms to use JWTs across the board, but there is one workflow that would be great if there was an easy way to spit out a JWT from the library.
In my user registration workflow, they fill in their data, I add them to the database (after validation), I send them a confirmation mail, but now I'm requiring them to re-login to go through the @jwt_required workflow so I can return a JWT.
After registration, I want them to log in directly, so is there a way to extract a JWT (given that they just gave me their username/pass), without having to re-encode them manually?
Thanks!
-SJ
What is the timezone / jwt expiration that is being passed into the token?
I'm having trouble with validating the expiration date on a swift app end. The swift app side says it is expired even when it was just recently updated.
full stack trace:
Traceback (most recent call last): File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1836, in __call__ return self.wsgi_app(environ, start_response) File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1820, in wsgi_app response = self.make_response(self.handle_exception(e)) File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1403, in handle_exception reraise(exc_type, exc_value, tb) File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app response = self.full_dispatch_request() File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1477, in full_dispatch_request rv = self.handle_user_exception(e) File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1381, in handle_user_exception reraise(exc_type, exc_value, tb) File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1475, in full_dispatch_request rv = self.dispatch_request() File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1461, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "/usr/local/lib/python2.7/dist-packages/flask_jwt/__init__.py", line 176, in decorator _jwt_required(realm or current_app.config['JWT_DEFAULT_REALM']) File "/usr/local/lib/python2.7/dist-packages/flask_jwt/__init__.py", line 151, in _jwt_required token = _jwt.request_callback() File "/usr/local/lib/python2.7/dist-packages/flask_jwt/__init__.py", line 103, in _default_request_handler if parts[0].lower() != auth_header_prefix.lower(): IndexError: list index out of range
think that request_handler should have an additional check, for example:
auth_header_value = request.headers.get('Authorization', None)
if auth_header_value == '':
raise JWTError('Invalid JWT header', 'Empty value')
Issue is here:
https://github.com/mattupstate/flask-jwt/blob/master/flask_jwt/__init__.py#L78-L91
Setting the require and verify in the options does not actually make pyjwt verify those claims, they are simply ignored by pyjwt. If you wanted to do those verifications, you would need to decode the token first, and manually check if the keys are present
In _default_auth_request_handler() function, empty passwords are filtered out by the criterion = [username, password, len(data) == 2]
list.
This can be easily solved by changing the password
criteria to password is not None
I am using Flask as a back end (api) and angularjs as a front end. For JWTs I am using Flask-JWT in my api. And I was trying to configure angular-jwt in my front end
On login, I call /api/v1/auth (JWT_AUTH_URL_RULE) from angularjs app and I get the token. e.g.
eyJhbGciOiJIUzI1NiIsImV4cCI6MTQzMjExNTAzMiwiaWF0IjoxNDMyMTE1MDAyfQ.eyJ1c2VyX2lkIjoxfQ.dmwvvgDinqWojmZ9ff1wHk_gDYM-dXNG-uTrabY9fFM
Then I store it in localStorage
// angularjs code
localStorage['id_token'] = data.token;
But when I try to decode it in another part of my app, I get null
// angularjs code
console.log('token expiration date', jwtHelper.getTokenExpirationDate(localStorage.getItem('id_token')));
console.log('token expired', jwtHelper.isTokenExpired(localStorage.getItem('id_token')));
Note that the algorithms that I have tried for SECURITY_PASSWORD_HASH are
bcrypt, sha512_crypt, or pbkdf2_sha512
// SECURITY_PASSWORD_HASH from https://pythonhosted.org/Flask-Security/configuration.html
Why doesn't it work?
In fact I see it getting decoded in http://jwt.io/
The current docs specify that the authentication handler "should return an object representing an authenticated identity." but its not clear what exactly that means. Digging into the source I can see that the only thing that is important is the id
property/key.
I think it would be useful to note that in the docs.
https://github.com/mattupstate/flask-jwt/blob/master/flask_jwt/__init__.py#L113-L128
and
https://github.com/mattupstate/flask-jwt/blob/master/flask_jwt/__init__.py#L182-L193
401 is Unauthorized
400 is Bad Request
401 Bad Request is not a thing.
https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1
It looks like the default was changed in this commit
I'm not sure if the default should be changed back, or if the default request handler should return Unauthorized instead. There appears to be some back and forth here.
The RFC appears to indicate that 400 Bad Request is the "most correct" response, but stack overflow, and some RESTful examples seem to interpret 401 Unauthorized more loosely, and return 401 when users fail to provide the correct credentials.
def _default_decode_handler(token):
"""Return the decoded token."""
try:
result = _get_serializer().loads(token)
except SignatureExpired:
if current_app.config['JWT_VERIFY_EXPIRATION']:
raise
return result
Even if not checking expiration is not recommended, it should still be an option, but since timed serializer will not deserialize, it raises:
UnboundLocalError: local variable 'result' referenced before assignment
Hi,
Wondering what is the plan on a new release on pypi? There have been some code changes that would be useful to get.
Thx!
I'm currently using github-flask to allow my users to authenticate - you think its possible to avoid cookies to remember the session and instead use flask-jwt?
Thanks!
Traceback (most recent call last):
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask/app.py", line 1836, in call
return self.wsgi_app(environ, start_response)
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask_restful/init.py", line 265, in error_router
return original_handler(e)
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask/_compat.py", line 32, in reraise
raise value.with_traceback(tb)
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask_restful/init.py", line 265, in error_router
return original_handler(e)
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask/_compat.py", line 32, in reraise
raise value.with_traceback(tb)
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functionsrule.endpoint
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask_restful/init.py", line 446, in wrapper
resp = resource(_args, *_kwargs)
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask/views.py", line 84, in view
return self.dispatch_request(_args, *_kwargs)
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/flask_restful/init.py", line 550, in dispatch_request
resp = meth(_args, *_kwargs)
File "/Volumes/Unsigned/server/application/models/user.py", line 45, in post
return {'status': 200, 'message': generate_token(user)} # TODO : SESSION!
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/src/flask-jwt/flask_jwt/init.py", line 147, in generate_token
token = _jwt.encode_callback(payload)
File "/Volumes/Unsigned/server/application/models/user.py", line 88, in encode_handler
return t.dumps(payload).decode('utf-8')
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/itsdangerous.py", line 742, in dumps
return signer.sign(self.dump_payload(header, obj))
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/itsdangerous.py", line 353, in sign
return value + want_bytes(self.sep) + self.get_signature(value)
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/itsdangerous.py", line 348, in get_signature
sig = self.algorithm.get_signature(key, value)
File "/usr/local/var/lib/pyenv/versions/3.4.2-server/lib/python3.4/site-packages/itsdangerous.py", line 268, in get_signature
mac = hmac.new(key, msg=value, digestmod=self.digest_method)
File "/usr/local/var/lib/pyenv/versions/3.4.2/lib/python3.4/hmac.py", line 144, in new
return HMAC(key, msg, digestmod)
File "/usr/local/var/lib/pyenv/versions/3.4.2/lib/python3.4/hmac.py", line 42, in init
raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).name)
TypeError: key: expected bytes or bytearray, but got 'NoneType'
When using flask-jwt how to exempt flask-wtf CSRF for POST requests??
Would love a guide into how to use flask-jwt and flask-wtf together but have csrf exempt from the authentication using the application factory approach. Thanks!
I'd like to get the current_identity in routes where authorization is not required. For instance a list of news items, if they are logged in they can comment, otherwise no commenting allowed.
Is there another way to get the current_identity of a user if they are logged in from a route that's not decorated with @jwt_required?
Hi!.
Im running exactly the example of GitHub. When I try get the token the log tell me this:
File "C:\Python34\lib\site-packages\flask_jwt__init__.py", line 114, in _def
ult_auth_request_handler
username = data.get(current_app.config.get('JWT_AUTH_USERNAME_KEY'), None)
AttributeError: 'NoneType' object has no attribute 'get'
Im checking the code and I see nothing
Is exactly the same code of the example.
Any suggestion?.
I'd like to be able to catch ExpiredSignatureError
, DecodeError
and other specific exceptions and do something meaningful with them, but they aren't exposed for import. I can only import JWTError
, but I see more specific exceptions 'escaping' (eg: DecodeError
).
Further on an expired signature for example, internal to flask-jwt a ExpiredSignatureError
is generated, but is later exposed externally as a JWTError
with only a description that the token has expired which makes exception handling awkward as I have to inspect the text of the description rather than just catching on the exception type itself.
Can these errors be exposed externally so they can be imported and used externally?
Thanks!
This is a small issue:
making a wrong request to the auth resource, like sending a form data instead of json data, an Internal Server Error occurs. I think that Bad Request may be a better response. I saw your code, _default_auth_request_handler method in details, but i didn't found the problem.
When I have debug = True in the flask application, and I make a call to a jwt protected endpoint without an access token I get the following back:
{
"description": "Request does not contain an access token",
"error": "Authorization Required",
"status_code": 401
}
However, when I try the same thing with debug = False, instead I get this:
{"message": "Internal Server Error"}
And in the logs, I see:
flask_jwt.JWTError: Authorization Required. Request does not contain an access token
As far as I can tell, the jwt.init_app() function is registering a custom error handler for JWTErrors in the flask app, however it only seems to be working when flask debug is enabled. Any ideas why this might be the case?
Hi there.
Quick question , is there a way to "reset" a token expiration time based on activity?
in the sense that token should not expire after timeout if it's being used...
i see this parameter in other implementations "JWT_ALLOW_REFRESH'"
Thanks!
Hello,
After I have gotten the token using JWT_AUTH_URL_RULE
, how do invalidate it?
I wanna create an action for /logout
. On logout I want the token to expire/become invalid
How do I do this?
As a part of 0.3 branch and migration to PyJWT a number of JWT methods got renamed, prefixed with 'jwt_' and others have not:
0.2 | 0.3 |
---|---|
authentication_handler | authentication_handler |
identity_handler | identity_handler |
error_handler | **jwt_**error_handler |
request_handler | request_handler |
encode_handler | **jwt_**encode_handler |
decode_handler | **jwt_**decode_handler |
payload_handler | **jwt_**payload_handler |
headers_handler | **jwt_**headers_handler |
Did I miss some?
I don't quite understand, why some got prefixed and others didn't (there isn't any collision with "import jwt" functions as far as I can tell). Migrating from 0.2 is somewhat a headache experience because of the missing link. That and the fact that method docs still refer to old names like "jwt.payload_handler".
Thanks.
In my app I want to be able to use just a custom login token (on app start) to authenticate and get a JWT token. Right now as far as I know a username and password is required, is there any way to change this?
I'm working on a project that requires using Python v2.6.6 on Centos 6.x. I am using the sample code published by this repo (https://github.com/mattupstate/flask-jwt/blob/master/example/app.py) and python is returning a syntax error from init.py:
Traceback (most recent call last): File "./wsgi.py", line 1, in from main import app as application File "./main.py", line 5, in from auth import api_auth File "./auth.py", line 3, in from flask_jwt import JWT File "/opt/mist_base/env/lib/python2.6/site-packages/flask_jwt/__init__.py", line 83 for claim in verify_claims ^ SyntaxError: invalid syntax
I assume this works for other people's instances, and I know there are issues using some libraries with v2.6.x - is this the case?
thx,
I write this issue KarimJedda/connexion_jwt_example#2 in the example using flask-jwt with Swagger api description.
I see that writing parameters in swagger api.yaml file, and decorating the controller with @jwt_required() the app crashed.
This is part of the yaml api description file,
paths:
'/stuff':
get:
tags: [stuff]
operationId: zblaaaa.get_secret
summary: Give me sugar sugar
parameters:
- name: animal_type
in: query
type: string
pattern: "^[a-zA-Z0-9]*$"
- name: limit
in: query
type: integer
minimum: 0
default: 100
responses:
200:
description: Something secret
and this is the controller function decorated with @jwt_required()
from run import jwt_required, current_identity
pets = {}
@jwt_required()
def get_secret(limit, animal_type=None):
return [pet for pet in pets.values() if not animal_type or pet['animal_type'] == animal_type][:limit]
the app crash with the following error
*flask_jwt/init.py", line 177 in decorator
return fn(args, kwargs)
TypeError: get_secret() takes at least 1 argument (0 given)
ERROR:run:Exception on /api/stuff [GET]
Traceback (most recent call last):
File "~/.pyenv/versions/miserver/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
....
File "~/.pyenv/versions/miserver/lib/python2.7/site-packages/connexion/decorators/validation.py", line 192, in wrapper
response = function(*args, **kwargs)
File "~/.pyenv/versions/miserver/lib/python2.7/site-packages/connexion/decorators/produces.py", line 117, in wrapper
data, status_code, headers = self.get_full_response(function(*args, **kwargs))
File "~/.pyenv/versions/miserver/lib/python2.7/site-packages/connexion/decorators/parameter.py", line 133, in wrapper
return function(*args, **kwargs)
File "~/.pyenv/versions/miserver/lib/python2.7/site-packages/flask_jwt/__init__.py", line 177, in decorator
return fn(*args, **kwargs)
TypeError: get_secret() takes at least 1 argument (0 given)
127.0.0.1 - - [2016-03-21 20:20:26] "GET /api/stuff?animal_type=dino&limit=100 HTTP/1.1" 500 377 0.003594
But without the decorator the app runs fine.
Thanks in advance
I'm new using JWT so I run the example where I find in docs. I read this https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/ to get a better understanding of JWT.
But now I wonder how I should handle more than one token?
I mean, a user post his credentials to "/auth" and then return a token to a client.
When the client send a new request he should sent the token.
My question is how I know what "token" belongs which user and where "tokens" are stored?
Should I store in database?
Because result is only set in one branch in _default_decode_handler.
Thoughts?
I was curious to know if anyone has figured out how you would mock jwt_required
decorator. In my unittests I would prefer not having to authenticate with my application. I thought setting the config
variable JWT_VERIFY
to False
would solve the issue, but as far as I understood the source this variable is never checked.
Thanks for your help.
Can you suggest how to go about testing views that are protected with the jwt_required
decorator?
Thanks much
It seems like you allow the user to overwrite the default decoder method, but _get_serializer is a private method. I want to add some extra steps to decoding (I'm adding functionality to track and revoke tokens), but I can't see how I can write a new decoder without also having to rewrite a serializer.
Thanks for creating this module!
-Eric
Hi,
I'm testing this project and the error handler have returned a 500 status code and not the status code that showed in this message:
in verify_jwt
'WWW-Authenticate': 'JWT realm="%s"' % realm
flask_jwt.JWTError: ('Authorization Required', 'Authorization header was missing', 401, {'WWW-Authenticate': 'JWT realm="Login Required"'})
My first idea was to create a specific class to handle it, but reading the source code you already did it. So, I just followed the example to create a error_handler function available on the docstring.
Some idea?
[ ]'s
I'm getting the following error, however if I run the example it works quite good!
Then, I don't know if I'm doing something really wrong (as solo, it works!) or is some kind of bug, somehow.
Traceback (most recent call last):
File "\\mypath\.venv\lib\site-packages\flask\app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "\\mypath\.venv\lib\site-packages\flask\app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "\\mypath\.venv\lib\site-packages\flask\app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "\\mypath\.venv\lib\site-packages\flask\_compat.py", line 33, in reraise
raise value
File "\\mypath\.venv\lib\site-packages\flask\app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "\\mypath\.venv\lib\site-packages\flask\app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "\\mypath\.venv\lib\site-packages\flask\app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "\\mypath\.venv\lib\site-packages\flask\_compat.py", line 33, in reraise
raise value
File "\\mypath\.venv\lib\site-packages\flask\app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "\\mypath\.venv\lib\site-packages\flask\app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "\\mypath\.venv\lib\site-packages\flask\views.py", line 84, in view
return self.dispatch_request(*args, **kwargs)
File "\\mypath\.venv\lib\site-packages\flask\views.py", line 149, in dispatch_request
return meth(*args, **kwargs)
File "\\mypath\.venv\lib\site-packages\flask_jwt\__init__.py", line 154, in post
token = _jwt.encode_callback(payload)
File "\\mypath\.venv\lib\site-packages\flask_jwt\__init__.py", line 50, in _default_encode_handler
return _get_serializer().dumps(payload).decode('utf-8')
File "\\mypath\.venv\lib\site-packages\itsdangerous.py", line 742, in dumps
return signer.sign(self.dump_payload(header, obj))
File "\\mypath\.venv\lib\site-packages\itsdangerous.py", line 353, in sign
return value + want_bytes(self.sep) + self.get_signature(value)
File "\\mypath\.venv\lib\site-packages\itsdangerous.py", line 348, in get_signature
sig = self.algorithm.get_signature(key, value)
File "\\mypath\.venv\lib\site-packages\itsdangerous.py", line 268, in get_signature
mac = hmac.new(key, msg=value, digestmod=self.digest_method)
File "\\mypath\.venv\lib\hmac.py", line 144, in new
return HMAC(key, msg, digestmod)
File "\\mypath\.venv\lib\hmac.py", line 42, in __init__
raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
TypeError: key: expected bytes or bytearray, but got 'NoneType'
my directory structure is as follows:
where app.py has:
from flask import Flask
# JWT
from flask_jwt import JWT
app = Flask(__name__)
jwt = JWT(app)
auth.py:
from app import app, db, jwt
from flask_jwt import jwt_required
class User(object):
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
@app.route('/protected')
@jwt_required()
def protected():
return 'Success!'
@jwt.authentication_handler
def authenticate(username, password):
# import pdb; pdb.set_trace()
if username == 'joe' and password == 'pass':
return User(id=1, username='joe')
@jwt.user_handler
def load_user(payload):
if payload['user_id'] == 1:
return User(id=1, username='joe')
and main.py:
from app import app
from auth import *
from api import *
from views import *
if __name__ == '__main__':
app.run(debug=True)
Hey, I'm trying to overwrite the default payload_callback but I can't, what I'm doing wrong?
@jwt.jwt_payload_callback
def make_payload(u):
print "YEAH"
print "YEAH"
iat = datetime.utcnow()
exp = iat + timedelta(seconds=60)
nbf = iat + timedelta(seconds=0)
return {'iat': iat, 'exp': exp, 'nbf': nbf, 'id': u.id, 'role': u.role}
I would expect to see in payload next result:
{'iat': iat, 'exp': exp, 'nbf': nbf, 'id': u.id, 'role': u.role}
Hi, I was having good luck with your package so far, but when I tried to integrate it with my Flask-restful resource classes, I ran into issues. Is there a way to use this decorator with Resource classes? Here is a code snippet and error. Thanks!
class Events(Resource):
@marshal_with(eventFields, envelope="events")
@jwt_required
def get(self):
return events.values()
Traceback (most recent call last):
File "/opt/iat/IaT5.1/usr/local/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/opt/iat/IaT5.1/usr/local/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functionsrule.endpoint
File "/opt/iat/IaT5.1/usr/local/lib/python2.7/site-packages/flask_restful/init.py", line 431, in wrapper
resp = resource(_args, *_kwargs)
File "/opt/iat/IaT5.1/usr/local/lib/python2.7/site-packages/flask/views.py", line 84, in view
return self.dispatch_request(_args, *_kwargs)
File "/opt/iat/IaT5.1/usr/local/lib/python2.7/site-packages/flask_restful/init.py", line 521, in dispatch_request
resp = meth(_args, *_kwargs)
File "/opt/iat/IaT5.1/usr/local/lib/python2.7/site-packages/flask_restful/init.py", line 613, in wrapper
resp = f(_args, *_kwargs)
File "/opt/iat/IaT5.1/usr/local/lib/python2.7/site-packages/flask_jwt/init.py", line 85, in wrapper
@wraps(fn)
File "/opt/iat/IaT5.1/usr/local/lib/python2.7/functools.py", line 33, in update_wrapper
setattr(wrapper, attr, getattr(wrapped, attr))
AttributeError: 'Events' object has no attribute 'name'
It looks like the current author is looking for a maintainer of this software: https://twitter.com/mattupstate/status/790184050640162816. I wrote another jwt flask extension that offers what this extension does, plus some extra goodies on top:
You can view the code here (link to the documentation is in the readme)
https://github.com/vimalloc/flask-jwt-extended
I was thinking of reaching out to the author and trying to merge my extension into this one. However, it might cause some pretty big breaking changes. I could probably alleviate most of them by making sure all the functionality of this extension existed in mine, but marking the breaking changes as depreciated, in order to give users a chance to migrate their code. But before I start looking at that, I was wondering if anyone would actually be interested in this? I would love to get feedback before I offered to start making changes that people may not want.
If the SECRET_KEY field is not specified, you get a really cryptic exception from pyjwt as follows:
def prepare_key(self, key):
if not is_string_type(key):
> raise TypeError('Expecting a string- or bytes-formatted key.')
E TypeError: Expecting a string- or bytes-formatted key.
../../.virtualenvs/flask-praetorian/lib/python3.5/site-packages/jwt/algorithms.py:116: TypeError
An exception should be raised in init_app if that configuration is not set
my config is :
JWT_AUTH_URL_RULE = "/api/v1/auth"
JWT_VERIFY_EXPIRATION = False
I use token for my mobile app. I want that my token never expired, but it doesn't work.
Do you have an idea ?
Internally Flask-JWT are using the TimedJSONWebSignatureSerializer from its dangerous. Unfortunately this ISN'T a JWT generator. Instead it creates a JWS with some extra information in the header like 'exp'.
According to the JWT specification, all the claims are supposed to be part of the payload NOT the header. (They are allowed to be replicated in the header, but not if omitted in the payload)
This seems to me as quite a big misunderstanding of the specification and should be rectified
I'm currently using flask-jwt in my project with angularjs frontend. The users can get the token providing the user/pass and everything works just fine.
The problem appeared when I needed to get a token to authenticate an external application. I did the following:
@api_bp.route("/external_auth/<id_key>/<json_hash>")
def external_auth(id_key,json_hash):
external_api_key = ExternalApiKey.query.get(id_key)
if external_api_key == None:
abort(401)
# blalbalbla specific app code
return json.dumps({"token":generate_jwt_token({"user_id":data['user_id'], ... extra params})})
As I didn't want to use app/password for the external api calls, but I needed the token I basically used your code to generate a token with my custom payload.
from flask import current_app
from itsdangerous import (
TimedJSONWebSignatureSerializer,
SignatureExpired,
BadSignature
)
from datetime import timedelta
def generate_jwt_token(payload):
expires_in = current_app.config['JWT_EXPIRATION_DELTA']
if isinstance(expires_in, timedelta):
expires_in = int(expires_in.total_seconds())
expires_in_total = expires_in + current_app.config['JWT_LEEWAY']
serializer = TimedJSONWebSignatureSerializer(
secret_key=current_app.config['JWT_SECRET_KEY'],
expires_in=expires_in_total,
algorithm_name=current_app.config['JWT_ALGORITHM']
)
return serializer.dumps(payload).decode('utf-8')
My question is... is there any "pretty" way to access your flask_jwt code to do this? I feel like using private functions or objects doesn't looks nice, so that's why I duplicated most of the token generation code.
authenticate and identity must be created and imported prior to jwt.init_app? is there a better way for application factory?
# auth_handlers.py
@jwt.authentication_handler
def authenticate(username, password):
user = username_table.get(username, None)
if user and safe_str_cmp(user.password.encode('utf-8'), password.encode('utf-8')):
return user
@jwt.identity_handler
def identity(payload):
user_id = payload['identity']
return userid_table.get(user_id, None)
#extensions.py
from flask_jwt import JWT
jwt = JWT()
etc...
# app.py
from extensions import jwt
from flask_jwt import jwt_required
def create_app():
app = Flask(__name__)
app.debug = True
app.config['SECRET_KEY'] = 'super-secret'
register_extenstions(app)
return app
def register_extensions(app):
another_app.init_app(app)
another_app.init_app(app)
from auth_handlers import authenticate, identity <<<<<< This looks really ugly
jwt.init_app(app)
another_app.init_app(app)
another_app.init_app(app)
another_app.init_app(app)
app = create_app()
@app.route('/protected')
@jwt_required()
def protected():
return '%s' % current_identity
if __name__ == '__main__':
app.run(port=1234)
If no secret key is set (that is, None
), the following error is reported:
TypeError: Expecting a string- or bytes-formatted key.
A more helpful message would be nice.
I think that if user provides bad credentials, return code should be 401. 400 would mean that the request is malformed:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
flask_jwt/init.py:168
from flask import Flask
from flask_jwt import JWT, jwt_required, current_identity
from werkzeug.security import safe_str_cmp
class User(object):
def init(self, id, username, password):
self.id = id
self.username = username
self.password = password
def __str__(self):
return "User(id='%s')" % self.id
users = [ User(1,'user1','abcxyz'),User(2,'user2','abcxyz'),]
username_table = {u.username: u for u in users}
userid_table = {u.id: u for u in users}
def authenticate(username, password):
user = username_table.get(username, None)
if user and safe_str_cmp(user.password.encode('utf-8'), password.encode('utf-8')):
return user
def identity(payload):
user_id = payload['identity']
return userid_table.get(user_id, None)
app = Flask(name)
app.config['SECRET_KEY'] = 'super-secret'
jwt = JWT(app, authenticate, identity)
@app.route('/protected')
@jwt_required()
def protected():
return '%s' % current_identity
if name == 'main':
app.run(debug=True)
//my request like this
The example for the header_handler is a copy-paste of pauload_handlers example:
Have had great success using this library with angular-jwt... until attempting to implement client side token expiry notifications...
the angular-jwt module has a function to check if a token is expired, it is looking in the JWT body for the exp claim - however it appears flask-jwt is writing the exp and iat to the JWT header by default?
Am I doing something wrong? or should the exp and iat be contained within the body?
Any help would be great, thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.