Skip to content

Commit 3430f12

Browse files
committed
Small improvement to existing code. Added more detailed notes in README.md
1 parent f790cb7 commit 3430f12

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

sections_flask-jwt-extended/README.md

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,30 @@ This section presents the basic usage of an active flask JWT extension called `f
1010
- Blacklist and token revoking
1111
- Customize JWT response/error message callbacks
1212

13+
### JWT authentication
14+
15+
Very much the same as before, but we define a UserLogin resource ourselves, as opposed to having a `/auth` endpoint created internally. And we no longer need the `security.py` file consequently.
16+
17+
### Token Refreshing
18+
19+
It allows the user login without having to entering the username and password over and over again. When logging in, we get an access token as before, and we also get a refresh token. We can use this refresh token to generate new access tokens without enter user credentials when the current access token expires.
20+
21+
### Fresh token vs. Non-fresh token
22+
23+
When generating an access token, we can pass in an optional boolean argument `fresh`. We usually want to distinguish if the token is generated via credentials or via refresh token. Since the one generated with credentials should be considered more secure. So what we did in the project is to return a **fresh** access token and a refresh token from the `/login` endpoint, since user would need to provide their credentials to authenticate through `/login`. As for the `/refresh` endpoint, it only requires a refresh token and no credentials, so it would return a non-fresh access token. The non-fresh access token still gives us some belief that it's the user himself, but it is not that secure. So it's okay to allow the user to access most endpoints using a non-fresh token, but we may want the user to input his credentials again (to get a fresh access token) when performing some more important actions, such as deleting things or payment.
24+
25+
### Adding claims to JWT payload
26+
27+
We can also add some extra data to each JWT payload, and these data are accessible within the endpoint. We refer to these data as `claims`. We can attach any claims we find necessary to the JWT payload. In this section, we showed one use case, where we check if the authenticated user is an admin, and added a boolean claim `is_admin` to the payload. Then in each JWT-protected endpoint, we can tell if the user is ad admin, and decide what actions should be taken from there.
28+
29+
### Blacklist and token revoking
30+
31+
We can blacklist a user or revoke a token (access token or refresh token) and disable the user from logging in and accessing a protected endpoint. Possible use cases for this feature include: if a user complains his account being compromised, or we decide to take down an existing account temporarily, we can blacklist the user and revoke the token thus prevent the user from logging in.
32+
33+
### Customize JWT messages
34+
35+
The default response/error handler may not have the nicest format of output. It uses clueless abbreviation such as `iat` for `issue at time` and `msg` for `message`. We can customize the callbacks and display the message we felt more readable.
36+
1337
## Related Resources
1438

1539
### UserLogin
@@ -41,8 +65,46 @@ This section presents the basic usage of an active flask JWT extension called `f
4165
- Description: get all items, half protected. User can get more detailed info when providing an access token.
4266
- Request header: `Authorization Bearer <access_token>`
4367

44-
68+
## Suggested introduction order
69+
70+
Here is a recommended flow of modifying the previous code and introduces Flask-JWT-Extended features.
71+
72+
### Logging in with Flask-JWT-Extended
73+
74+
We used the `/login` endpoint, defined in `UserLogin` resource. Focus on the similarities and differences from `Flask-JWT` authentication. Do not introduce refresh token and token freshness yet. Talk about JWT protected endpoint as well, since it's also similar with the previous Flask-JWT extension. Use the `Item.get()` endpoint as example.
75+
76+
tips:
77+
- Resource is now defined by us, not internally by library anymore.
78+
- Customized url
79+
- `@jwt_required` now as opposed to `@jwt_required()`
80+
81+
### Adding claims to JWT payload
82+
83+
Introduce the concept of `claims`, it's just the data we choose to attach to the JWT payload. Use the `Item.delete()` endpoint as example, we make it only accessible by authenticated admins. So we need to configure the claims in `app.py` and decide whether a user is an admin, then we add a boolean claim `is_admin` to the JWT payload.
84+
85+
tips:
86+
- `get_jwt_oidentity()` now as opposed to `current_identity`
87+
- The identity is just the user id now as opposed to a UserModel object.
88+
89+
### Half protected endpoints
90+
91+
Introduce `@jwt_optional` decorator, which makes the endpoint accessible with and without an access token. Change the `ItemList.get()` endpoint to return different response depending on whether the caller is an authenticated user.
92+
93+
### Token Refresh
94+
95+
Introduce another endpoint, `/refresh`, for token refreshing. Add a refresh token in the previous `/login` endpoint response, and show how to get a new access token using the refresh token, without entering user credentials.
96+
97+
tips:
98+
- don't worry about token freshness for now (non-fresh by default)
99+
100+
### Token freshness
101+
102+
Talk about security concerns, and then introduce token freshness concept and the recommended way of using fresh/non-fresh access tokens. Then we return a fresh access token in the `/login` endpoint and return a non-fresh access token in the `/refresh` endpoint. Then introduce `@fresh_jwt_required` decorator for `Item.post()` endpoint, and show how non-fresh token would fail to call the endpoint compared to fresh access tokens.
45103

104+
### Customize response/error callbacks
46105

106+
Talk about the differences between the error/response messages from the previous `Flask-JWT` messages, it may be not as readable as the previous ones. Show how we can customize the messages.
47107

108+
### Blacklisting and token revoking
48109

110+
Keep on talking about customizing callbacks, as well as security issue. Introduce blacklisting and token revoking here.

sections_flask-jwt-extended/app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
@jwt.user_claims_loader
3434
def add_claims_to_jwt(identity):
3535
if identity == 1: # instead of hard-coding, we can read from a config file to get a list of admins instead
36-
return {'isAdmin': True}
37-
return {'isAdmin': False}
36+
return {'is_admin': True}
37+
return {'is_admin': False}
3838

3939

4040
black_list = [4, 6] # user.id that are black listed (can be read from a file or db too)

sections_flask-jwt-extended/resources/item.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def post(self, name):
4949
@jwt_required
5050
def delete(self, name):
5151
claims = get_jwt_claims()
52-
if not claims['isAdmin']:
52+
if not claims['is_admin']:
5353
return {'message': 'Admin privilege required.'}, 401
5454

5555
item = ItemModel.find_by_name(name)

0 commit comments

Comments
 (0)