The Problem

While building a Facebook Messenger bot integration, I ran into a frustrating bug: users who connected their Facebook Page would mysteriously get no answers at all, when asking questions through Messenger.

After digging through logs, I found the root cause: two different user IDs were in play.

What Was Happening

Our app had two separate flows:

  1. Portal login — email/password authentication, storing userId in Redux/localStorage and User table in database.
  2. Facebook Page connect — OAuth flow to link a Facebook Page to the account

The document upload (RAG ingest) used the portal userId. But when a message arrived via Messenger webhook, we looked up Page.adminId to query the RAG service, and that adminId belonged to a completely different, (new)user.

Why It Created a Second User

The facebookPagesCallback was implemented as a full OAuth login flow, not as "attach FB token to current user":

// Wrong approach
const user = await authService.findOrCreateOAuthUser({
provider: 'facebook',
providerId: profile.id,
email: `fb_${profile.id}@facebook.placeholder`, // never matches real email
name: profile.name,
});
const token = authService.generateTokenForOAuthUser(user);
setAuthCookie(res, token); // overwrites existing session!

The placeholder email fb_<id>@facebook.placeholder never matched the existing portal account, so findOrCreateOAuthUser always created a new ghost user. Then setAuthCookie overwrote the session with this ghost user's JWT.

Result:

  • RAG document indexed under portal user ID
  • Page.adminId stored as ghost user ID
  • Webhook queries RAG with ghost ID → no documents found

The Fix

The fix was simple, don't treat FB Page connect as a login. Just grab the Facebook access token and redirect back with it, keeping the existing portal session intact:

// Correct approach
public facebookPagesCallback = async (req, res) => {
const { code } = req.query;
const tokenRes = await fetch(`https://graph.facebook.com/v18.0/oauth/access_token?...`);
const { access_token } = await tokenRes.json();
// No user creation. No cookie overwrite. Just pass the token.
res.redirect(`${clientUrl}/upload?fb_connected=1&…..`);
};

The frontend then sends fb_token to POST /api/pages, where req.user is already the correct portal user — so Page.adminId gets set correctly.

The Lesson

OAuth "connect" and OAuth "login" are different things. If a user is already authenticated, attaching a third-party service should never create a new identity or overwrite their session. Always ask: am I logging someone in, or am I linking an external service to an existing account?