11# Flask-JWT-Extended
22Flask-JWT-Extended adds support for using JSON Web Tokens (JWT) to Flask for protecting views.
33
4- This has built in support for entirely stateless 'vanilla' JSON Web Tokens. It also has optional [ refresh tokens] (https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/ ), token freshness (reuqires users to re-authenticate if they haven't in a while when accessing critical views), and optional token revokation (stateful).
4+ This has several optional features built it to make working with JSON Web Tokens
5+ easier. These include:
56
6- Token revokation makes no assumption about your underlying storage for revoked tokens. It uses [ simplekv] (https://github.com/mbr/simplekv ) to utilize the underlying storage of your choice.
7+ * Support for adding custom claims to JSON Web Tokens
8+ * [ Refresh tokens] (https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/ )
9+ * Token freshness and separate view decorators to only allow fresh tokens
10+ * Token revoking
711
812# Installation
913The easiest way to start working with this extension with pip:
@@ -48,6 +52,12 @@ if __name__ == '__main__':
4852 app.run()
4953```
5054
55+ To access a ** jwt_required** protected view, all we have to do is send an authorization
56+ head with the request that include the token. The header looks like this:
57+ ```
58+ Authorization: Bearer <access_token>
59+ ```
60+
5161We can see this in action using CURL:
5262```
5363$ curl --write-out "%{http_code}\n" http://localhost:5000/protected
@@ -70,14 +80,14 @@ $ curl --write-out "%{http_code}\n" -H "Authorization: Bearer $ACCESS" http://lo
7080}
7181200
7282```
73- However, this is only the tip of the iceberg for what we can do
7483
75-
76- ### Adding Custom Claims to the Access Token
84+ ### Adding Custom Data (Claims) to the Access Token
7785You may want to store additional information in the access token. Perhaps you want
7886to save the access roles this user has so you can access them in the view functions
7987(without having to make a database call each time). This can be done with the
80- user_claims_loader, and access with the 'get_jwt_claims()' method in a protected endpoint
88+ ** user_claims_loader** decorator, and accessed later with the 'get_jwt_claims()'
89+ method (in a protected endpoint).
90+
8191``` python
8292from flask import Flask, jsonify, request
8393from flask_jwt_extended import JWTManager, jwt_required, create_access_token, \
@@ -125,8 +135,8 @@ if __name__ == '__main__':
125135Flask-JWT-Extended supports [ refresh tokens] (https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/ )
126136out of the box. These are longer lived token which cannot access a jwt_required protected
127137endpoint, but can be used to create new access tokens once an old access token has expired.
128- By setting the access tokens to a shorter lifetime (see Options bellow ), and utilizing
129- fresh tokenks for critical endpoint (see Fresh Tokens bellow ) we can help reduce the
138+ By setting the access tokens to a shorter lifetime (see Options below ), and utilizing
139+ fresh tokens for critical views (see Fresh Tokens below ) we can help reduce the
130140damage done if an access token is stolen. Here is an example on how to use them:
131141
132142``` python
@@ -172,33 +182,30 @@ def protected():
172182if __name__ == ' __main__' :
173183 app.run()
174184```
175- As you can see, there are a few things different in this example. First and formost
176- is the create_refresh_token method, which as the name implies, will generate a new
177- refresh token. Second is the @ jwt_refresh_token_required decorator. This will
185+ As you can see, there are a few things different in this example. First and foremost
186+ is the ** create_refresh_token** method, which as the name implies, will generate a new
187+ refresh token. Second is the ** jwt_refresh_token_required** decorator. This will
178188protect a view so that it can only be accessed if a valid refresh token is supplied
179189in the request (an access token cannot access this view). Finally, we have the
180- method get_jwt_identity. This will return the identity of the token used to access
190+ method ** get_jwt_identity** . This will return the identity of the token used to access
181191this endpoint (and works for both access and refresh tokens).
182192
183- We can now this refresh token to generate new access tokens without the user having
184- to login with their username and passwords all the time. Neat. Now lets look at
185- token freshness to see how we can improve upon this further.
186193
187194### Token Freshness
188- We have the idea of token freshness built into this system . In a nutshell, you can
195+ We have the idea of token freshness built into this extension . In a nutshell, you can
189196choose to mark some access tokens as fresh and others as non-fresh, and a
190- fresh_jwt_required decorator to only allow fresh tokens to access some views.
197+ ** fresh_jwt_required** decorator to only allow fresh tokens to access some views.
191198
192199This is useful for allowing fresh logins to do some critical things (maybe change
193200a password, or complete an online purchase), but to deny those features to
194201non-fresh tokens without verifying their username/password. This still allows your
195202users to access any of the normal jwt_protected endpoints while using a non-fresh
196- token. Using these wisely can lead to a more secure site, without creating
197- unnecessarily bad users experiences by having to re-login all the time.
203+ token. Using these can lead to a more secure site, without creating a burden
204+ on the users experiences by forcing them to re-authenticate all the time.
198205
199206The provided API gives you the power to use the token freshness however you may
200207want to. A very natural way to do this would be to mark a token as fresh when they
201- first login, mark any tokens generated with the refresh token to be not fresh,
208+ first login, mark any tokens generated with the refresh token to as not fresh,
202209and provide one more endpoint for generating new fresh tokens (via re-authing)
203210without generating a new refresh token to go with it.
204211``` python
@@ -256,23 +263,25 @@ def protected():
256263
257264@app.route (' /protected-fresh' , methods = [' GET' ])
258265@fresh_jwt_required
259- def protected ():
266+ def protected_fresh ():
260267 username = get_jwt_identity()
261268 return jsonify({' hello' : ' from {} ' .format(username)}), 200
262269
263270if __name__ == ' __main__' :
264271 app.run()
265272```
266- The only real things to note here is the new @fresh_jwt_required decorator, and
267- the optional 'fresh=' keyword passed to the 'create_access_token' methods.
273+ As you can see here, there is an optional ** fresh** keyword argument in the
274+ ** create_access_token** method, which will control the token freshness. This,
275+ in combination with the ** fresh_jwt_required** decorator can protect your critical
276+ views with only fresh tokens.
268277
269278### Changing Default Behaviors
270- We provide what we think are sensible behaivors when attempting to access a protected
271- endpoint. If the endpoint could not be used for any reason (missing/expired/invalid/etc
272- access token) we will return json in the format of {'msg': <why accesing endpoint failed >}
273- along with an appropiate http status code (generally 401 or 422). However, you may want
274- to cusomize what is sent back in these cases . We can do that with the jwt_manager
275- 'loader' functions.
279+ We provide what we think are sensible behaviors when attempting to access a protected
280+ endpoint. If the endpoint could not be used for any reason (missing/expired/invalid
281+ access token, etc ) we will return json in the format of {'msg': <why accesing endpoint failed >}
282+ along with an appropriate http status code (generally 401 or 422). However, you may want
283+ to customize what is returned for a given case . We can do that with the jwt_manager
284+ ** _ loader ** functions.
276285``` python
277286from flask import Flask, jsonify, request
278287from flask_jwt_extended import JWTManager, jwt_required, create_access_token
@@ -311,7 +320,7 @@ if __name__ == '__main__':
311320 app.run()
312321```
313322Now if an expired token tries to access the protected endpoint, we will get the
314- json we specified back instead of our default behaivor .
323+ json we specified back instead of the default implementation .
315324
316325The available loader functions are:
317326* expired_token_loader
@@ -340,27 +349,26 @@ will only check refresh tokens, and 'all' which will check refresh and access to
340349to 'refresh'
341350
342351### Blacklist and Token Revoking
343- This supports blacklisting and token revoking out of the box. This will allow you
344- to revoke a specific token so a user can no longer access your endpoints, without
345- having to change your secret key and thus revoke all the users tokens. In order
352+ This supports optional blacklisting and token revoking out of the box. This will allow you
353+ to revoke a specific token so a user can no longer access your endpoints. In order
346354to revoke a token, we need some storage where we can save a list of all the tokens
347- we have created, as well as if they have been blacklisted or not. In order to make
355+ we have created, as well as if they have been revoked or not. In order to make
348356the underlying storage as agnostic as possible, we use [ simplekv] (http://pythonhosted.org/simplekv/ )
349- to provide assess to a variaty of backends.
357+ to provide assess to a variety of backends.
350358
351359In production, it is important to use a backend that can have some sort of
352360persistent storage, so we don't forget that we revoked a token, as well as
353361something that can be safely used by the multiple thread and processes running
354362your application. At present we believe redis is a good fit for this (it has the
355363added benefit of removing expired tokens from the store automatically, so it
356- wont blow up into something huge). But the choice is of course yours.
364+ wont blow up into something huge). The choice is of course yours.
357365
358366We also have to make a choice of if we want to check the blacklist against all
359367requests, or only against refresh token requests. There are pros and cons to either
360368way (extra overhead on jwt_required endpoints vs someone being able to use an
361369access token freely until it expires). In this example, we are going to only check
362370refresh tokens, and set the access tokes to a small expires time to help minimize
363- damange that could be done.
371+ damage that could be done with a stolen access token .
364372``` python
365373from datetime import timedelta
366374
0 commit comments