|
1 | 1 | from flask import Flask |
2 | 2 | from flask import jsonify |
3 | | -from flask import request |
4 | 3 |
|
5 | 4 | from flask_jwt_extended import create_access_token |
6 | | -from flask_jwt_extended import create_refresh_token |
7 | 5 | from flask_jwt_extended import get_jwt |
8 | | -from flask_jwt_extended import get_jwt_identity |
9 | | -from flask_jwt_extended import jwt_refresh_token_required |
10 | 6 | from flask_jwt_extended import jwt_required |
11 | 7 | from flask_jwt_extended import JWTManager |
12 | 8 |
|
| 9 | +# In production make sure to use persistent storage, such as a database or redis |
| 10 | +blocklist = set() |
13 | 11 |
|
14 | | -# Setup flask |
15 | 12 | app = Flask(__name__) |
16 | | - |
17 | | -# Enable blocklisting and specify what kind of tokens to check |
18 | | -# against the blocklist |
19 | 13 | app.config["JWT_SECRET_KEY"] = "super-secret" # Change this! |
20 | 14 | jwt = JWTManager(app) |
21 | 15 |
|
22 | | -# A storage engine to save revoked tokens. In production if |
23 | | -# speed is the primary concern, redis is a good bet. If data |
24 | | -# persistence is more important for you, postgres is another |
25 | | -# great option. In this example, we will be using an in memory |
26 | | -# store, just to show you how this might work. For more |
27 | | -# complete examples, check out these: |
28 | | -# https://github.com/vimalloc/flask-jwt-extended/blob/master/examples/redis_blocklist.py |
29 | | -# https://github.com/vimalloc/flask-jwt-extended/tree/master/examples/database_blocklist |
30 | | -blocklist = set() |
31 | | - |
32 | 16 |
|
33 | | -# For this example, we are just checking if the tokens jti |
34 | | -# (unique identifier) is in the blocklist set. This could |
35 | | -# be made more complex, for example storing all tokens |
36 | | -# into the blocklist with a revoked status when created, |
37 | | -# and returning the revoked status in this call. This |
38 | | -# would allow you to have a list of all created tokens, |
39 | | -# and to consider tokens that aren't in the blocklist |
40 | | -# (aka tokens you didn't create) as revoked. These are |
41 | | -# just two options, and this can be tailored to whatever |
42 | | -# your application needs. |
| 17 | +# The `jti` claim in the jwt_payload is a unique identifier (string) for the JWT. |
43 | 18 | @jwt.token_in_blocklist_loader |
44 | | -def check_if_token_in_blocklist(decrypted_token): |
45 | | - jti = decrypted_token["jti"] |
| 19 | +def check_if_token_in_blocklist(jwt_header, jwt_payload): |
| 20 | + jti = jwt_payload["jti"] |
46 | 21 | return jti in blocklist |
47 | 22 |
|
48 | 23 |
|
49 | | -# Standard login endpoint |
50 | 24 | @app.route("/login", methods=["POST"]) |
51 | 25 | def login(): |
52 | | - username = request.json.get("username", None) |
53 | | - password = request.json.get("password", None) |
54 | | - if username != "test" or password != "test": |
55 | | - return jsonify({"msg": "Bad username or password"}), 401 |
56 | | - |
57 | | - ret = { |
58 | | - "access_token": create_access_token(identity=username), |
59 | | - "refresh_token": create_refresh_token(identity=username), |
60 | | - } |
61 | | - return jsonify(ret), 200 |
62 | | - |
| 26 | + access_token = create_access_token(identity="example_user") |
| 27 | + return jsonify(access_token=access_token) |
63 | 28 |
|
64 | | -# Standard refresh endpoint. A blocklisted refresh token |
65 | | -# will not be able to access this endpoint |
66 | | -@app.route("/refresh", methods=["POST"]) |
67 | | -@jwt_refresh_token_required |
68 | | -def refresh(): |
69 | | - current_user = get_jwt_identity() |
70 | | - ret = {"access_token": create_access_token(identity=current_user)} |
71 | | - return jsonify(ret), 200 |
72 | 29 |
|
73 | | - |
74 | | -# Endpoint for revoking the current users access token |
| 30 | +# On logout, add the token to our blocklist. |
75 | 31 | @app.route("/logout", methods=["DELETE"]) |
76 | | -@jwt_required |
| 32 | +@jwt_required() |
77 | 33 | def logout(): |
78 | 34 | jti = get_jwt()["jti"] |
79 | 35 | blocklist.add(jti) |
80 | | - return jsonify({"msg": "Successfully logged out"}), 200 |
81 | | - |
82 | | - |
83 | | -# Endpoint for revoking the current users refresh token |
84 | | -@app.route("/logout2", methods=["DELETE"]) |
85 | | -@jwt_refresh_token_required |
86 | | -def logout2(): |
87 | | - jti = get_jwt()["jti"] |
88 | | - blocklist.add(jti) |
89 | | - return jsonify({"msg": "Successfully logged out"}), 200 |
| 36 | + return jsonify(msg="Successfully logged out") |
90 | 37 |
|
91 | 38 |
|
92 | | -# This will now prevent users with blocklisted tokens from |
93 | | -# accessing this endpoint |
| 39 | +# A revoked token will not be able to access this route. |
94 | 40 | @app.route("/protected", methods=["GET"]) |
95 | | -@jwt_required |
| 41 | +@jwt_required() |
96 | 42 | def protected(): |
97 | | - return jsonify({"hello": "world"}) |
| 43 | + return jsonify(hello="world") |
98 | 44 |
|
99 | 45 |
|
100 | 46 | if __name__ == "__main__": |
|
0 commit comments