JSON Web Tokens (JWTs) are a compact, URL-safe means of representing claims to be transferred between two parties. In the context of web applications, they are commonly used for authorization. A server generates a JWT upon successful user authentication and sends it to the client. The client then includes this JWT in subsequent requests to access protected resources. The server can verify the token's authenticity and validity without needing to query a database every time.
`flask-jwt-extended` is a Flask extension that provides a full suite of utilities for working with JWTs. It simplifies the process of adding JWT-based authentication to your Flask applications. Key features include:
1. Token Creation: Easily generate `access_token` and `refresh_token` for authenticated users.
2. Token Verification: Decorators like `@jwt_required` automatically verify incoming tokens.
3. Identity Management: Retrieve the identity of the current user from the token payload.
4. Token Refreshing: Allows clients to obtain new access tokens using a refresh token without re-authenticating.
5. Token Blacklisting/Revocation: Provides mechanisms to invalidate JWTs, important for security events like logout or password changes.
6. Flexible Storage: Supports sending tokens via headers, query parameters, or cookies.
How it works:
- Login: When a user logs in successfully, the application creates an `access_token` and often a `refresh_token`. The `access_token` is short-lived and used for protected API calls. The `refresh_token` is long-lived and used to obtain new `access_token`s after the old one expires.
- Protected Routes: Routes requiring authentication are decorated with `@jwt_required`. When a request hits such a route, `flask-jwt-extended` extracts the JWT from the request (typically from the `Authorization` header), verifies its signature, expiration, and other claims. If valid, the request proceeds; otherwise, an unauthorized error is returned.
- Token Refresh: When an `access_token` expires, the client sends the `refresh_token` to a designated refresh endpoint. If the `refresh_token` is valid, a new `access_token` is issued.
- Logout/Revocation: To invalidate a token before its natural expiration, `flask-jwt-extended` provides hooks for blacklisting tokens. This typically involves storing invalidated token IDs in a database or cache.
Example Code
from flask import Flask, jsonify, request
from flask_jwt_extended import (
JWTManager,
create_access_token,
jwt_required,
get_jwt_identity,
create_refresh_token,
jwt_refresh_token_required,
get_raw_jwt,
set_access_cookies,
set_refresh_cookies,
unset_jwt_cookies
)
--- Configuration ---
app = Flask(__name__)
Setup the Flask-JWT-Extended extension
app.config["JWT_SECRET_KEY"] = "super-secret-jwt-key" Change this in production!
app.config["JWT_TOKEN_LOCATION"] = ["cookies"] Where to look for JWTs
app.config["JWT_COOKIE_SECURE"] = False Set to True in production (HTTPS only)
app.config["JWT_CSRF_PROTECTION"] = True Enable CSRF protection for cookies
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = 60 - 5 Access token valid for 5 minutes
app.config["JWT_REFRESH_TOKEN_EXPIRES"] = 60 - 60 - 24 - 7 Refresh token valid for 7 days
jwt = JWTManager(app)
--- In-memory store for revoked tokens (for demonstration) ---
In a real application, use a persistent store like Redis or a database.
BLACKLIST = set()
Callback function to check if a JWT has been revoked
@jwt.token_loader
def check_if_token_in_blacklist(decrypted_token):
jti = decrypted_token['jti']
return jti in BLACKLIST
--- Dummy User Data (for demonstration) ---
users = {
"testuser": {"password": "testpass", "roles": ["user"]},
"admin": {"password": "adminpass", "roles": ["admin", "user"]}
}
--- Routes ---
@app.route('/login', methods=['POST'])
def login():
username = request.json.get('username', None)
password = request.json.get('password', None)
user_data = users.get(username)
if not user_data or not user_data['password'] == password:
return jsonify({"msg": "Bad username or password"}), 401
Create the tokens. We can add additional claims here if needed.
access_token = create_access_token(identity=username, expires_delta=app.config["JWT_ACCESS_TOKEN_EXPIRES"])
refresh_token = create_refresh_token(identity=username, expires_delta=app.config["JWT_REFRESH_TOKEN_EXPIRES"])
Set the cookies in the response
resp = jsonify({"login": True})
set_access_cookies(resp, access_token)
set_refresh_cookies(resp, refresh_token)
return resp, 200
@app.route('/protected', methods=['GET'])
@jwt_required
def protected():
Access the identity of the current user with get_jwt_identity
current_user = get_jwt_identity()
return jsonify(logged_in_as=current_user), 200
@app.route('/refresh', methods=['POST'])
@jwt_refresh_token_required
def refresh():
Create a new access token, using the identity from the refresh token.
current_user = get_jwt_identity()
new_access_token = create_access_token(identity=current_user, expires_delta=app.config["JWT_ACCESS_TOKEN_EXPIRES"])
Set the new access token in the response cookies
resp = jsonify({"refresh": True})
set_access_cookies(resp, new_access_token)
return resp, 200
@app.route('/logout', methods=['POST'])
def logout():
When logging out, we need to revoke the access token.
In a real app, you might also revoke the refresh token, or just rely on its expiration.
For simplicity, this example just clears the cookies.
resp = jsonify({"logout": True})
unset_jwt_cookies(resp) Removes the access and refresh token cookies
Optionally, you could blacklist the current access token's JTI
to immediately invalidate it, even if the cookies are cleared.
jti = get_raw_jwt()['jti'] Needs @jwt_required to get token details
BLACKLIST.add(jti)
return resp, 200
--- Main ---
if __name__ == '__main__':
app.run(debug=True, port=5000)
To test this application:
1. Run the Flask app.
2. Use a tool like Postman or curl to send requests.
Example Curl Commands:
Login:
curl -X POST -H "Content-Type: application/json" -d '{"username": "testuser", "password": "testpass"}' http://127.0.0.1:5000/login -c cookie-jar.txt
Access Protected Resource (after login):
curl -X GET http://127.0.0.1:5000/protected -b cookie-jar.txt
Refresh Token (after access token expires or just to get a new one):
curl -X POST http://127.0.0.1:5000/refresh -b cookie-jar.txt -c cookie-jar.txt
Logout:
curl -X POST http://127.00.1:5000/logout -b cookie-jar.txt -c cookie-jar.txt








JWT Flask Integration with flask-jwt-extended