Skip to content

bug: Broken OAuth Flow between Node.js and Flask due to JWT Verification Mismatch #147

Description

@onkar0127

Description:

Problem Summary

The GMail and Outlook email scanning connections are completely non-functional. When the Node.js backend handles OAuth callbacks or tries to fetch/scan emails, it queries the Python Flask ML API. It identifies the user by forwarding their username in the X-User-Username header.

However, the Flask API routes are decorated with @jwt_required(). Because the Node.js server does not forward a Flask-signed JWT, the request fails immediately with a 401 Unauthorized response. Even if the JWT token check is bypassed, the Flask route expects username = get_jwt_identity() to identify the user session, which evaluates to None.


Location of Bug

  • Node.js Axios request wrapper: server.js (L394-L405)
  • Flask Python endpoints: api.py (L355-L360) (and similar callback/email scanner routes)

Steps to Reproduce

  1. Run both the Node.js and Flask backend servers.
  2. Log into the React frontend application.
  3. Navigate to the Email Scanner tab and click Connect Gmail or Connect Outlook.
  4. Authorize through the OAuth screen.
  5. Once redirected, the connection state fails, and checking logs reveals a 401 Unauthorized JWT verification error from the Python API.

Code Context

1. Node.js backend sending the request:

// backend/server.js
app.get("/gmail/connect", protect, async (req, res) => {
  try {
    const { code } = req.query;
    const response = await axios.get(`${ML_API_BASE}/gmail/callback`, {
      params: { code },
      headers: {
        "X-User-Username": req.user.username, // Only X-User-Username is sent, NO Flask JWT
      },
    });
    res.json(response.data);
  } catch (error) { ... }
});

2. Flask API receiving the request:

# backend/api.py
@app.route("/gmail/callback", methods=["GET"])
@jwt_required() # Expects a Flask-signed Authorization JWT header
def gmail_callback():
    code = request.args.get("code")
    username = get_jwt_identity() # Evaluates to None because no Flask JWT was passed
    # ... code fails to match user tokens store

Suggested Fix

We need to implement a mechanism for internal microservice authentication. Two viable solutions include:

  1. Option A (Recommended): Shared Secret API Key
    Introduce an internal api-key auth helper in the Flask app. If a request is received from the Node server with a valid api-key header (e.g., X-Internal-Secret), trust the X-User-Username header instead of requesting a JWT check.

  2. Option B: Shared JWT Secret
    Share the JWT_SECRET_KEY between the Node.js backend and Flask API so that Flask can verify the JWT token generated by the Node backend directly.

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions