python Logoflask-jwt-extended

flask-jwt-extended is a powerful Flask extension that provides a flexible way to add JWT (JSON Web Token) based authentication to your Flask applications. It simplifies the process of creating, managing, and verifying JWTs, making it easier to secure your API endpoints.

What are JWTs?
JWTs are an open, industry-standard RFC 7519 method for representing claims securely between two parties. They are commonly used for authorization where the client sends a token with each request, and the server verifies it to ensure the client is authenticated and authorized to access the requested resource. JWTs are stateless, meaning the server doesn't need to store session information, which can improve scalability.

Key Features of flask-jwt-extended:
1. Access and Refresh Tokens: Supports the common pattern of using short-lived access tokens for securing resources and long-lived refresh tokens for acquiring new access tokens without re-authenticating.
2. Decorators for Endpoint Protection: Provides easy-to-use decorators like `@jwt_required()`, `@fresh_jwt_required()`, and `@jwt_refresh_token_required()` to protect routes based on the token type.
3. Token Creation and Verification: Functions to programmatically create access and refresh tokens (`create_access_token`, `create_refresh_token`) and handle their verification automatically through decorators.
4. Custom Claims: Allows embedding custom data (claims) into your JWTs, which can be retrieved later to access user-specific information.
5. Token Blacklisting: Provides a mechanism to invalidate tokens (e.g., on logout or password change) by storing their JTI (JWT ID) in a blacklist, preventing them from being used for authentication.
6. Cookies and Headers Support: Can send and receive JWTs via HTTP Only cookies (recommended for browser-based applications) or through the `Authorization` header.
7. Identity Management: Easily retrieve the identity of the current user from a valid JWT using `get_jwt_identity()`.
8. Configuration Options: Extensive configuration options for secret keys, token lifetimes, token locations, and more.

How it Works (Typical Flow):
1. User Login: A user sends credentials to a login endpoint.
2. Token Creation: If credentials are valid, the server creates an access token and a refresh token, signing them with a secret key.
3. Token Return: These tokens are sent back to the client, usually in the response body or as HTTP Only cookies.
4. Protected Resource Access: For subsequent requests to protected routes, the client includes the access token (e.g., in the `Authorization` header).
5. Token Verification: The `flask-jwt-extended` decorator on the server-side verifies the access token's signature, expiration, and ensures it's not blacklisted.
6. Refresh Token Usage: When an access token expires, the client uses the refresh token to request a new access token from a refresh endpoint.
7. Logout: Upon logout, the server adds the access and/or refresh token's JTI to a blacklist, rendering them unusable.

This library is ideal for building secure APIs with Flask, providing a robust and flexible authentication solution that decouples token management from session management.

Example Code

from flask import Flask, jsonify, request
from flask_jwt_extended import (
    JWTManager, jwt_required, create_access_token,
    create_refresh_token, get_jwt_identity, jwt_refresh_token_required,
    set_access_cookies, set_refresh_cookies, unset_jwt_cookies, get_jwt
)

app = Flask(__name__)

 Setup the Flask-JWT-Extended extension
app.config["JWT_SECRET_KEY"] = "super-secret-key-that-should-be-in-env"
app.config["JWT_TOKEN_LOCATION"] = ["cookies"]
app.config["JWT_COOKIE_SECURE"] = False   Set to True in production (HTTPS)
app.config["JWT_COOKIE_CSRF_PROTECT"] = True
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = 3600  1 hour
app.config["JWT_REFRESH_TOKEN_EXPIRES"] = 2592000  30 days
jwt = JWTManager(app)

 A simple set to store blacklisted JWT JTIs
 In a real application, this would be a persistent storage like Redis or a database
blacklist = set()

 Callback function to check if a JWT has been blacklisted
@jwt.token_in_blocklist_loader
def check_if_token_in_blocklist(jwt_header, jwt_payload):
    jti = jwt_payload["jti"]
    return jti in blacklist

 A simple 'user' database for demonstration
users = {
    "testuser": {"password": "testpass"}
}

@app.route('/login', methods=['POST'])
def login():
    username = request.json.get('username', None)
    password = request.json.get('password', None)

    if not username or not password:
        return jsonify({"msg": "Missing username or password"}), 400

    if username not in users or users[username]['password'] != password:
        return jsonify({"msg": "Bad username or password"}), 401

     Create the tokens
    access_token = create_access_token(identity=username)
    refresh_token = create_refresh_token(identity=username)

     Set the JWTs in http-only cookies
    response = jsonify({"msg": "Login successful"})
    set_access_cookies(response, access_token)
    set_refresh_cookies(response, refresh_token)
    return response, 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 from the refresh token
    current_user = get_jwt_identity()
    new_access_token = create_access_token(identity=current_user)

     Set the new access token in a http-only cookie
    response = jsonify({"msg": "Token refreshed"})
    set_access_cookies(response, new_access_token)
    return response, 200

@app.route('/logout', methods=['POST'])
@jwt_required()
def logout():
     Retrieve the JTI (JWT ID) from the access token to blacklist it
    jti = get_jwt()["jti"]
    blacklist.add(jti)

    response = jsonify({"msg": "Successfully logged out"})
    unset_jwt_cookies(response)
    return response, 200

@app.route('/logout_refresh', methods=['POST'])
@jwt_refresh_token_required()
def logout_refresh():
     Blacklist the refresh token
    jti = get_jwt()["jti"]
    blacklist.add(jti)

    response = jsonify({"msg": "Successfully logged out (refresh token)"})
    unset_jwt_cookies(response)
    return response, 200

if __name__ == '__main__':
    app.run(debug=True)