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:
- Portal login — email/password authentication, storing userId in Redux/localStorage and User table in database.
- 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?