Skip to content

Commit d3268d8

Browse files
committed
Cleanup up some things in the README
1 parent 298e24d commit d3268d8

File tree

2 files changed

+46
-38
lines changed

2 files changed

+46
-38
lines changed

README.md

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
# Flask-JWT-Extended
22
Flask-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
913
The 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+
5161
We 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
}
7181
200
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
7785
You may want to store additional information in the access token. Perhaps you want
7886
to 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
8292
from flask import Flask, jsonify, request
8393
from flask_jwt_extended import JWTManager, jwt_required, create_access_token, \
@@ -125,8 +135,8 @@ if __name__ == '__main__':
125135
Flask-JWT-Extended supports [refresh tokens] (https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/)
126136
out of the box. These are longer lived token which cannot access a jwt_required protected
127137
endpoint, 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
130140
damage 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():
172182
if __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
178188
protect a view so that it can only be accessed if a valid refresh token is supplied
179189
in 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
181191
this 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
189196
choose 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

192199
This is useful for allowing fresh logins to do some critical things (maybe change
193200
a password, or complete an online purchase), but to deny those features to
194201
non-fresh tokens without verifying their username/password. This still allows your
195202
users 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

199206
The provided API gives you the power to use the token freshness however you may
200207
want 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,
202209
and provide one more endpoint for generating new fresh tokens (via re-authing)
203210
without 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

263270
if __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
277286
from flask import Flask, jsonify, request
278287
from flask_jwt_extended import JWTManager, jwt_required, create_access_token
@@ -311,7 +320,7 @@ if __name__ == '__main__':
311320
app.run()
312321
```
313322
Now 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

316325
The 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
340349
to '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
346354
to 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
348356
the 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

351359
In production, it is important to use a backend that can have some sort of
352360
persistent storage, so we don't forget that we revoked a token, as well as
353361
something that can be safely used by the multiple thread and processes running
354362
your application. At present we believe redis is a good fit for this (it has the
355363
added 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

358366
We also have to make a choice of if we want to check the blacklist against all
359367
requests, or only against refresh token requests. There are pros and cons to either
360368
way (extra overhead on jwt_required endpoints vs someone being able to use an
361369
access token freely until it expires). In this example, we are going to only check
362370
refresh 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
365373
from datetime import timedelta
366374

examples/token_freshness.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def protected():
5252

5353
@app.route('/protected-fresh', methods=['GET'])
5454
@fresh_jwt_required
55-
def protected():
55+
def protected_fresh():
5656
username = get_jwt_identity()
5757
return jsonify({'hello': 'from {}'.format(username)}), 200
5858

0 commit comments

Comments
 (0)