HIGH jwt misconfigurationflaskapi keys

Jwt Misconfiguration in Flask with Api Keys

Jwt Misconfiguration in Flask with Api Keys — how this specific combination creates or exposes the vulnerability

JWT misconfiguration in a Flask API that also exposes API keys creates a compound attack surface. When JWT handling is inconsistent and API keys are used as an additional authorization mechanism, attackers can bypass intended protections by targeting the weaker component.

Common JWT misconfigurations include not validating the signature, using none algorithm, failing to verify the issuer (iss) or audience (aud), accepting unsigned tokens, or mishandling token expiration. In Flask, developers sometimes load JWTs with jwt.decode(token, options={"verify_signature": False}) during debugging and forget to remove it, or they omit algorithm specification, which may default to expecting HS256 while the server actually accepts unsigned tokens.

Simultaneously, API keys in Flask are often passed via headers (e.g., X-API-Key) and validated with simple string comparisons or database lookups. If the API key check occurs after JWT validation, an attacker with a malformed or unsigned JWT may gain access to endpoints where the API key gate is not enforced, or the server may inadvertently treat a missing or weak key as acceptable when combined with a trusted JWT.

The risk is amplified when token validation logic is scattered, some routes rely solely on JWT while others rely on API keys, and configuration differs between environments. An attacker can probe for these inconsistencies—such as sending a valid-looking JWT with an invalid algorithm and a missing or weak API key—to identify which control is lax and pivot through the authorization boundary.

Real-world impacts include unauthorized access to user data, elevation to privileged operations, and exposure of sensitive endpoints. This aligns with OWASP API Top 10 controls related to broken object level authorization and insufficient authentication, and can be discovered by scanners running parallel checks such as BOLA/IDOR and Authentication alongside API key validation tests.

Api Keys-Specific Remediation in Flask — concrete code fixes

Remediation focuses on consistent validation, strict configuration, and clear separation of concerns between JWT and API key checks. Below are concrete, secure patterns for Flask.

1. Enforce strict JWT validation

Always specify the algorithm and validate claims. Avoid options={"verify_signature": False} in production.

import jwt
from flask import request, jsonify

def verify_jwt(token):
    try:
        decoded = jwt.decode(
            token,
            key="your-256-bit-secret",
            algorithms=["HS256"],
            options={"verify_signature": True, "require": ["exp", "iat", "iss", "aud"]},
            issuer="myapi.example.com",
            audience="my-client-app"
        )
        return decoded
    except jwt.ExpiredSignatureError:
        raise InvalidToken("Token expired")
    except jwt.InvalidTokenError:
        raise InvalidToken("Invalid token")

2. Centralize API key validation

Use a before-request handler to validate the API key for routes that require it, and avoid mixing it with JWT logic.

from flask import request, g

VALID_API_KEYS = {"sk_live_abc123", "sk_test_xyz789"}

def validate_api_key():
    api_key = request.headers.get("X-API-Key")
    if not api_key or api_key not in VALID_API_KEYS:
        return jsonify({"error": "Invalid or missing API key"}), 401
    g.api_key = api_key

@app.before_request
def before_request():
    if request.endpoint in ["admin_export", "billing_report"]:
        r = validate_api_key()
        if r:
            return r

3. Ensure consistent authorization across methods

Do not allow one authentication method to implicitly satisfy another. Require explicit validation for each protected route.

@app.route("/admin/users")
def admin_users():
    auth = request.headers.get("Authorization")
    if not auth or not auth.startswith("Bearer "):
        return jsonify({"error": "Missing bearer token"}), 401
    token = auth.split(" ")[1]
    claims = verify_jwt(token)
    if claims.get("role") != "admin":
        return jsonify({"error": "Insufficient scope"}), 403
    # proceed with admin logic

4. Harden key handling and storage

Store API keys as environment variables or via a secrets manager. Never hardcode them in source files.

import os
from flask import Flask

app = Flask(__name__)
app.config["VALID_API_KEYS"] = set(os.environ.get("API_KEYS", "").split(","))

5. Use middleware or extensions for separation

Consider Flask extensions for structured auth, and keep JWT and API key checks distinct to reduce misconfiguration risk.

# Example structure
@app.route("/data")
def get_data():
    token = request.headers.get("Authorization")
    if token and token.startswith("Bearer "):
        claims = verify_jwt(token.split(" ")[1])
        if claims:
            return jsonify({"source": "jwt", "data": "protected"})
    api_key = request.headers.get("X-API-Key")
    if api_key and api_key in current_app.config["VALID_API_KEYS"]:
        return jsonify({"source": "api_key", "data": "protected"})
    return jsonify({"error": "Unauthorized"}), 401

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

Why does mixing JWT and API key checks increase risk in Flask APIs?
Mixing mechanisms without clear boundaries can lead to inconsistent enforcement. If one control is weaker or skipped, attackers can bypass protections by exploiting the less strict method, increasing the likelihood of unauthorized access.
How can I test whether my Flask API is vulnerable to JWT or API key misconfigurations?
Use a scanner that runs multiple checks in parallel, such as Authentication, BOLA/IDOR, and API key validation. These tests probe for unsigned tokens, missing claim validation, and weak or missing API keys to identify misconfigurations.