Skip to content

Commit e66ff3d

Browse files
committed
Loader examples
1 parent 49330a9 commit e66ff3d

File tree

5 files changed

+96
-10
lines changed

5 files changed

+96
-10
lines changed

README.md

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,58 @@ The only real things to note here is the new @fresh_jwt_required decorator, and
218218
the optional 'fresh=' keyword passed to the 'create_access_token' methods.
219219

220220
### Changing Default Behaviors
221-
TODO
221+
We provide what we think are sensible behaivors when attempting to access a protected
222+
endpoint. If the endpoint could not be used for any reason (missing/expired/invalid/etc
223+
access token) we will return json in the format of {'msg': <why accesing endpoint failed>}
224+
along with an appropiate http status code (generally 401 or 422). However, you may want
225+
to cusomize what is sent back in these cases. We can do that with the jwt_manager
226+
'loader' functions.
227+
```python
228+
from flask import Flask, jsonify, request
229+
from flask_jwt_extended import JWTManager, jwt_required, create_access_token
230+
231+
app = Flask(__name__)
232+
app.secret_key = 'super-secret' # Change this!
233+
jwt = JWTManager(app)
234+
235+
236+
@jwt.expired_token_callback
237+
def my_expired_token_callback():
238+
return jsonify({
239+
'status': 401,
240+
'sub_status': 101,
241+
'msg': 'The token has expired'
242+
}), 200
243+
244+
245+
@app.route('/login', methods=['POST'])
246+
def login():
247+
username = request.json.get('username', None)
248+
password = request.json.get('password', None)
249+
if username != 'test' and password != 'test':
250+
return jsonify({"msg": "Bad username or password"}), 401
251+
252+
ret = {'access_token': create_access_token(username)}
253+
return jsonify(ret), 200
254+
255+
256+
@app.route('/protected', methods=['GET'])
257+
@jwt_required
258+
def protected():
259+
return jsonify({'hello': 'world'}), 200
260+
261+
if __name__ == '__main__':
262+
app.run()
263+
```
264+
Now if an expired token tries to access the protected endpoint, we will get the
265+
json we specified back instead of our default behaivor.
266+
267+
The available loader functions are:
268+
* expired_token_loader
269+
* invalid_token_loader (function takes one arg, which is an error string of why its invalid)
270+
* unauthorized_loader
271+
* needs_fresh_token_loader
272+
* revoked_token_loader (see Blacklist and Token Revoking bellow)
222273

223274
### Adding Custom Claims to the Access Token
224275
TODO

examples/loaders.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from flask import Flask, jsonify, request
2+
from flask_jwt_extended import JWTManager, jwt_required, create_access_token
3+
4+
app = Flask(__name__)
5+
app.secret_key = 'super-secret' # Change this!
6+
jwt = JWTManager(app)
7+
8+
9+
@jwt.expired_token_callback
10+
def my_expired_token_callback():
11+
return jsonify({
12+
'status': 401,
13+
'sub_status': 101,
14+
'msg': 'The token has expired'
15+
}), 200
16+
17+
18+
@app.route('/login', methods=['POST'])
19+
def login():
20+
username = request.json.get('username', None)
21+
password = request.json.get('password', None)
22+
if username != 'test' and password != 'test':
23+
return jsonify({"msg": "Bad username or password"}), 401
24+
25+
ret = {'access_token': create_access_token(username)}
26+
return jsonify(ret), 200
27+
28+
29+
@app.route('/protected', methods=['GET'])
30+
@jwt_required
31+
def protected():
32+
return jsonify({'hello': 'world'}), 200
33+
34+
if __name__ == '__main__':
35+
app.run()

flask_jwt_extended/jwt_manager.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def __init__(self, app=None):
2929

3030
# Function that will be called when attempting to access a fresh_jwt_required
3131
# endpoint with a valid token that is not fresh
32-
self.token_needs_refresh_callback = lambda: (
32+
self.needs_fresh_token_callback = lambda: (
3333
jsonify({'msg': 'Fresh token required'}), 401
3434
)
3535

@@ -100,7 +100,7 @@ def unauthorized_loader(self, callback):
100100
self.unauthorized_callback = callback
101101
return callback
102102

103-
def token_needs_refresh_loader(self, callback):
103+
def needs_fresh_token_loader(self, callback):
104104
"""
105105
Sets the callback method to be called if a valid and non-fresh token
106106
attempts to access an endpoint protected with @fresh_jwt_required.
@@ -110,7 +110,7 @@ def token_needs_refresh_loader(self, callback):
110110
111111
Callback must be a function that takes no arguments.
112112
"""
113-
self.token_needs_refresh_callback = callback
113+
self.needs_fresh_token_callback = callback
114114
return callback
115115

116116
def revoked_token_loader(self, callback):

flask_jwt_extended/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ def wrapper(*args, **kwargs):
179179
except RevokedTokenError:
180180
return m.revoked_token_callback()
181181
except FreshTokenRequired:
182-
return m.token_needs_refresh_callback()
182+
return m.needs_fresh_token_callback()
183183
return wrapper
184184

185185

tests/test_jwt_manager.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ def test_default_unauthorized_callback(self):
6262
self.assertEqual(status_code, 401)
6363
self.assertEqual(data, {'msg': 'Missing Authorization Header'})
6464

65-
def test_default_token_needs_refresh_callback(self):
65+
def test_default_needs_fresh_token_callback(self):
6666
with self.app.test_request_context():
6767
m = JWTManager(self.app)
68-
result = m.token_needs_refresh_callback()
68+
result = m.needs_fresh_token_callback()
6969
status_code, data = self._parse_callback_result(result)
7070

7171
self.assertEqual(status_code, 401)
@@ -133,15 +133,15 @@ def custom_unauthorized():
133133
self.assertEqual(status_code, 200)
134134
self.assertEqual(data, {'err': 'GOTTA LOGIN FOOL'})
135135

136-
def test_custom_token_needs_refresh_callback(self):
136+
def test_custom_needs_fresh_token_callback(self):
137137
with self.app.test_request_context():
138138
m = JWTManager(self.app)
139139

140-
@m.token_needs_refresh_loader
140+
@m.needs_fresh_token_loader
141141
def custom_token_needs_refresh():
142142
return jsonify({'sub_status': 101}), 200
143143

144-
result = m.token_needs_refresh_callback()
144+
result = m.needs_fresh_token_callback()
145145
status_code, data = self._parse_callback_result(result)
146146

147147
self.assertEqual(status_code, 200)

0 commit comments

Comments
 (0)