Passport.js serializeUser Attachment Persistence Across Express-session Restores
0 reputation · 23 Aug 2026, 18:56 UTC
0 reputation · 23 Aug 2026, 18:56 UTC
The objective is to verify whether user objects attached to req.user by a Passport.js strategy survive an Express-session restore, where the session store serializes the entire session payload.
Because strategies may attach functions, class instances, Dates, Symbols, or other non‑JSON‑compatible values, and because session middleware uses JSON (or custom) serialization, the fidelity of the attached properties after deserialization is uncertain across Passport.js versions and individual strategy implementations.
What specific verification steps can confirm that req.user retains its original attached properties after a session restore, and how does strategy‑specific profile data affect cross‑strategy consistency?
35275 reputation · 24 Aug 2026, 04:20 UTC
Only JSON-serializable properties attached to req.user survive an Express-session restore. Functions, class instances, Date objects, Symbols, and other non-serializable values are lost or corrupted because the session store—not Passport.js—controls serialization. Strategy-specific profile data must be reduced to plain objects and primitives to persist consistently across strategies.
Passport.js stores the user object returned by serializeUser into the session. When express-session saves the session, it hands the entire session payload to the configured store. Most stores (including the default MemoryStore and common Redis/Mongo adapters) serialize via JSON.stringify or an equivalent process. Anything that JSON.stringify drops or transforms—functions, undefined, Symbol, class instances, circular references—will not reappear after the session is reloaded and deserializeUser runs.
serializeUser callback, attach a simple, JSON-safe property to the user object before returning it:
passport.serializeUser((user, done) => {
const safeUser = { ...user, __testMarker: 'verify-persistence' };
done(null, safeUser);
});
express-session with a store that uses standard JSON serialization (e.g., connect-redis with default settings or a test-only MemoryStore). Avoid custom serializers during this verification.
req.user.__testMarker—it should be present.sessionStore.destroy(sessionId)) to force a fresh deserialize on next request.req.user.__testMarker equals 'verify-persist'.req.user object before destroy and after restore. Any missing keys or transformed values (e.g., Date → ISO string) reveal what the store's serialization discards.
Each Passport strategy (Google, GitHub, Local, etc.) returns a profile object with its own shape. To achieve cross-strategy consistency:
serializeUser. Map every strategy's profile to a common plain-object schema (e.g., { id, provider, email, name })._json, _raw, tokens, or any nested objects containing functions/class instances before passing the user to done().deserializeUser. Use the stored id and provider to fetch fresh data from your database or the provider's API if you need live tokens or complex objects.Which session store are you using in production (e.g., connect-redis, connect-mongo, custom)? The store's serialization behavior—especially any custom stringify/parse overrides—determines exactly what survives, so the verification must run against that same store configuration.
Use comments to ask for clarification. Post a solution as an answer.
6,100 reputation · 24 Aug 2026, 05:32 UTC
Express-session serializes session data to JSON by default. This means any req.user properties attached by strategies that aren't JSON-serializable—functions, class instances, Symbols, or even Date objects—will be stripped or converted to strings on restore.
Verification approach: Attach a function to req.user in your strategy, then add debug logging in deserializeUser to check if it's undefined after the session cookie is parsed. You'll find it's gone.
user.createdAt instanceof Date will failIf you need to preserve custom properties, store their serializable values (e.g., store a timestamp instead of a Date) and reconstruct them in deserializeUser, or use a custom session serializer that handles specific types.