Missing Authentication in Flask with Bearer Tokens
Missing Authentication in Flask with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Missing authentication in a Flask API that exposes Bearer token protection means endpoints intended to be protected accept requests without verifying the presence or validity of a token. This is distinct from a weak or broken implementation; it is the absence of any enforcement. When no route-level or application-level check validates an Authorization header, unauthenticated attackers can invoke sensitive operations directly.
Consider a Flask route that reads or modifies user data:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/api/users/me', methods=['GET'])
def get_current_user():
# No check for Authorization header
return jsonify({ 'profile': 'data' })
An attacker can call GET /api/users/me without any token and receive personal data. If the route performs actions such as deleting or updating records, the impact is more severe. This gap is common when developers rely on conventions, assume frontend enforcement is sufficient, or mistakenly believe that obscurity (e.g., non-guessable URLs) provides protection.
In the context of middleBrick’s 12 checks, Missing Authentication is identified when the scanner observes endpoints that should require a token but do not validate an Authorization header. The scanner also checks whether token validation logic is present and whether tokens are handled securely (e.g., not logged or accepted over insecure channels). Without proper validation, tokens cannot fulfill their role, and the API surface remains open.
Additionally, Bearer token misuse can compound the issue. For example, accepting tokens from any source (not just the Authorization header), failing to verify token signatures, or not checking scopes/roles can lead to privilege escalation or unauthorized data access. Even if authentication is present, improper validation can still expose functionality to attackers who obtain or guess a token.
Real-world attack patterns mirror this: enumeration of user IDs via predictable numeric IDs (BOLA/IDOR) often pairs with missing or weak authentication controls. If an endpoint like GET /api/users/123 lacks authentication, changing the ID yields other users’ data without any token. This aligns with OWASP API Top 10 categories such as Broken Object Level Authorization and Missing or Broken Authentication.
Bearer Tokens-Specific Remediation in Flask — concrete code fixes
Remediation centers on enforcing token validation on every protected route and ensuring tokens are handled securely. Below is a minimal, secure pattern using the flask and authlib libraries to validate Bearer tokens.
First, install the necessary package:
pip install Flask authlib
Then implement token validation:
from flask import Flask, request, jsonify
from authlib.integrations.flask_client import OAuth
from authlib.jose import jwt, JsonWebTokenError
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
app.config['OAUTH2_TOKEN_URL'] = 'https://auth.example.com/token'
# Example public key or JWKS endpoint for verifying JWT signatures
PUBLIC_KEY = open('public_key.pem').read()
def verify_token(token: str):
try:
claims = jwt.decode(token, PUBLIC_KEY)
claims.validate() # verifies exp, nbf, etc.
return claims
except JsonWebTokenError:
return None
@app.before_request
def require_auth():
# Skip auth for public endpoints if needed
if request.path.startswith('/api/public'):
return
auth = request.headers.get('Authorization')
if not auth or not auth.startswith('Bearer '):
return jsonify({ 'error': 'Unauthorized' }), 401
token = auth.split(' ')[1]
claims = verify_token(token)
if claims is None:
return jsonify({ 'error': 'Invalid token' }), 401
# Attach claims to request for downstream use
request.claims = claims
@app.route('/api/users/me', methods=['GET'])
def get_current_user():
claims = getattr(request, 'claims', None)
if not claims:
return jsonify({ 'error': 'Unauthorized' }), 401
user_id = claims.get('sub')
# Fetch user data based on subject claim
return jsonify({ 'user_id': user_id, 'profile': 'data' })
Key points in this pattern:
- Check for the
Authorizationheader and ensure it starts withBearer. - Validate the token signature using a trusted public key or JWKS endpoint to prevent accepting tampered tokens.
- Verify standard claims such as expiration (
exp) and not-before (nbf). - Reject requests with missing, malformed, or invalid tokens with a
401 Unauthorizedresponse. - Avoid logging raw tokens to prevent accidental exposure.
If you use a framework like Flask-JWT-Extended, the structure is similar but relies on its decorators:
from flask_jwt_extended import JWTManager, jwt_required, get_jwt_identity
app = Flask(__name__)
app.config['JWT_SECRET_KEY'] = 'super-secret'
jwt = JWTManager(app)
@app.route('/api/users/me', methods=['GET'])
@jwt_required()
def get_current_user():
current_user = get_jwt_identity()
return jsonify({ 'user_id': current_user, 'profile': 'data' })
Regardless of the library, ensure tokens are transmitted only over HTTPS and that scopes/roles encoded in the token are validated for each operation. middleBrick’s scans can highlight missing authentication checks and token validation gaps; the Pro plan’s continuous monitoring can help detect regressions over time, and the GitHub Action can fail builds when risk thresholds are exceeded.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |