0
# Session Management
1
2
User session handling including login/logout operations and user serialization/deserialization for persistent authentication state across requests. Sessions allow users to remain logged in across multiple requests.
3
4
## Capabilities
5
6
### User Serialization
7
8
Configure how user objects are serialized into and deserialized from the session.
9
10
```javascript { .api }
11
/**
12
* Register function to serialize user objects into the session (registration form)
13
* @param {Function} fn - Serialization function (user, done) => void or (user, req, done) => void
14
* @returns {Authenticator} Returns this for chaining
15
*/
16
passport.serializeUser(fn);
17
18
/**
19
* Execute user serialization (internal execution form)
20
* @param {Object} user - User object to serialize
21
* @param {Object} req - Express request object
22
* @param {Function} done - Callback function (err, serializedData) => void
23
*/
24
passport.serializeUser(user, req, done);
25
26
/**
27
* Register function to deserialize user objects from the session (registration form)
28
* @param {Function} fn - Deserialization function (id, done) => void or (id, req, done) => void
29
* @returns {Authenticator} Returns this for chaining
30
*/
31
passport.deserializeUser(fn);
32
33
/**
34
* Execute user deserialization (internal execution form)
35
* @param {any} obj - Serialized user data from session
36
* @param {Object} req - Express request object
37
* @param {Function} done - Callback function (err, user) => void
38
*/
39
passport.deserializeUser(obj, req, done);
40
```
41
42
**Usage Examples:**
43
44
```javascript
45
// Basic user serialization (store user ID)
46
passport.serializeUser((user, done) => {
47
done(null, user.id);
48
});
49
50
passport.deserializeUser((id, done) => {
51
User.findById(id, (err, user) => {
52
done(err, user);
53
});
54
});
55
56
// Store multiple user properties
57
passport.serializeUser((user, done) => {
58
done(null, {
59
id: user.id,
60
role: user.role,
61
lastLogin: user.lastLogin
62
});
63
});
64
65
passport.deserializeUser((sessionData, done) => {
66
User.findById(sessionData.id, (err, user) => {
67
if (err) return done(err);
68
if (!user) return done(null, false);
69
70
// Update last login tracking
71
user.lastLogin = sessionData.lastLogin;
72
done(null, user);
73
});
74
});
75
76
// Promise-based serialization (modern approach)
77
passport.serializeUser(async (user, done) => {
78
try {
79
done(null, user.id);
80
} catch (err) {
81
done(err);
82
}
83
});
84
85
passport.deserializeUser(async (id, done) => {
86
try {
87
const user = await User.findById(id);
88
done(null, user);
89
} catch (err) {
90
done(err);
91
}
92
});
93
```
94
95
### Request Authentication Methods
96
97
Methods added to HTTP request objects for managing user authentication state.
98
99
```javascript { .api }
100
/**
101
* Log user into request and session
102
* @param {Object} user - User object to log in
103
* @param {Object} [options] - Login options
104
* @param {boolean} [options.session=true] - Save login state in session
105
* @param {boolean} [options.keepSessionInfo=false] - Preserve existing session data
106
* @param {Function} callback - Callback function (err) => void
107
*/
108
req.logIn(user, options, callback);
109
req.login(user, options, callback); // Alias
110
111
/**
112
* Log user out of request and session
113
* @param {Object} [options] - Logout options
114
* @param {boolean} [options.keepSessionInfo=false] - Preserve session data after logout
115
* @param {Function} callback - Callback function (err) => void
116
*/
117
req.logOut(options, callback);
118
req.logout(options, callback); // Alias
119
120
/**
121
* Test if request is authenticated
122
* @returns {boolean} True if user is authenticated
123
*/
124
req.isAuthenticated();
125
126
/**
127
* Test if request is unauthenticated
128
* @returns {boolean} True if user is not authenticated
129
*/
130
req.isUnauthenticated();
131
```
132
133
**Usage Examples:**
134
135
```javascript
136
// Manual login after verification
137
app.post("/signup", async (req, res, next) => {
138
try {
139
const user = await User.create(req.body);
140
req.logIn(user, (err) => {
141
if (err) return next(err);
142
res.redirect("/dashboard");
143
});
144
} catch (err) {
145
next(err);
146
}
147
});
148
149
// Login without session
150
app.post("/api/login", (req, res, next) => {
151
passport.authenticate("local", (err, user) => {
152
if (err) return next(err);
153
if (!user) return res.status(401).json({ error: "Invalid credentials" });
154
155
req.logIn(user, { session: false }, (err) => {
156
if (err) return next(err);
157
res.json({ token: generateJWT(user) });
158
});
159
})(req, res, next);
160
});
161
162
// Logout with session cleanup
163
app.post("/logout", (req, res, next) => {
164
req.logOut((err) => {
165
if (err) return next(err);
166
res.redirect("/");
167
});
168
});
169
170
// Logout preserving some session data
171
app.post("/logout", (req, res, next) => {
172
req.logOut({ keepSessionInfo: true }, (err) => {
173
if (err) return next(err);
174
res.redirect("/");
175
});
176
});
177
178
// Authentication status checking
179
app.use("/admin", (req, res, next) => {
180
if (!req.isAuthenticated()) {
181
return res.redirect("/login");
182
}
183
if (req.user.role !== "admin") {
184
return res.status(403).send("Access denied");
185
}
186
next();
187
});
188
189
// API authentication middleware
190
app.use("/api", (req, res, next) => {
191
if (req.isUnauthenticated()) {
192
return res.status(401).json({ error: "Authentication required" });
193
}
194
next();
195
});
196
```
197
198
### Request Extension Properties
199
200
Internal properties added to HTTP request objects during initialization and authentication processes.
201
202
```javascript { .api }
203
/**
204
* Internal session manager reference (added by initialize middleware)
205
* Used by request methods to manage login/logout operations
206
*/
207
req._sessionManager;
208
209
/**
210
* Custom user property name (added by initialize middleware)
211
* Overrides default 'user' property when userProperty option is specified
212
* @type {string}
213
*/
214
req._userProperty;
215
216
/**
217
* Compatibility object for legacy strategy support (added by initialize middleware)
218
* @type {Object}
219
*/
220
req._passport;
221
222
/**
223
* Reference to passport instance (in compatibility mode)
224
* @type {Authenticator}
225
*/
226
req._passport.instance;
227
228
/**
229
* Current authenticated user object (dynamic property name)
230
* Property name defaults to 'user' but can be changed via userProperty option
231
* @type {Object|null}
232
*/
233
req[req._userProperty || 'user'];
234
235
/**
236
* Authentication information from strategy (added during authentication)
237
* Contains additional data provided by authentication strategy
238
* @type {Object|undefined}
239
*/
240
req.authInfo;
241
```
242
243
**Usage Examples:**
244
245
```javascript
246
// Initialize with custom user property
247
app.use(passport.initialize({ userProperty: 'currentUser' }));
248
249
// Access user via custom property
250
app.get('/profile', (req, res) => {
251
const user = req.currentUser; // Instead of req.user
252
res.json(user);
253
});
254
255
// Access authentication info
256
app.get('/api/profile',
257
passport.authenticate('bearer', { session: false }),
258
(req, res) => {
259
res.json({
260
user: req.user,
261
token: req.authInfo.token, // From bearer strategy
262
scope: req.authInfo.scope, // Additional auth info
263
client: req.authInfo.client // Client information
264
});
265
}
266
);
267
268
// Check internal properties (for debugging)
269
app.use((req, res, next) => {
270
console.log('Session Manager:', !!req._sessionManager);
271
console.log('User Property:', req._userProperty || 'user');
272
console.log('Passport Instance:', !!req._passport?.instance);
273
next();
274
});
275
```
276
277
### Session Strategy
278
279
Built-in strategy for restoring authentication state from sessions.
280
281
```javascript { .api }
282
/**
283
* Session strategy for authentication restoration
284
* @param {Object} [options] - Strategy options
285
* @param {string} [options.key='passport'] - Session key for storing user data
286
* @param {Function} deserializeUser - Function to deserialize user from session
287
*/
288
class SessionStrategy {
289
constructor(options, deserializeUser);
290
name: "session";
291
authenticate(req, options);
292
}
293
```
294
295
The SessionStrategy is automatically used by Passport and typically doesn't need manual configuration:
296
297
```javascript
298
// SessionStrategy is used automatically when you call:
299
app.use(passport.session());
300
301
// Which is equivalent to:
302
app.use(passport.authenticate("session"));
303
```
304
305
### Session Manager
306
307
Internal session manager handling login/logout operations with session regeneration and user serialization. Used internally by the Authenticator but can be accessed for advanced use cases.
308
309
```javascript { .api }
310
/**
311
* Session manager constructor with flexible parameter handling
312
* @param {Object|Function} [options] - Manager options or serializeUser function
313
* @param {string} [options.key='passport'] - Session storage key
314
* @param {boolean} [options.keepSessionInfo] - Preserve session data during regeneration
315
* @param {Function} serializeUser - Function to serialize user into session
316
*/
317
function SessionManager(options, serializeUser);
318
function SessionManager(serializeUser); // When first param is function
319
320
/**
321
* Log in a user by regenerating session and storing serialized user data
322
* @param {Object} req - Express request object with session
323
* @param {Object} user - User object to serialize and store
324
* @param {Object} [options] - Login options
325
* @param {boolean} [options.keepSessionInfo] - Preserve existing session data
326
* @param {Function} callback - Callback function (err) => void
327
*/
328
SessionManager.prototype.logIn = function(req, user, options, callback);
329
SessionManager.prototype.logIn = function(req, user, callback); // Options optional
330
331
/**
332
* Log out user by clearing session data and regenerating session
333
* @param {Object} req - Express request object with session
334
* @param {Object} [options] - Logout options
335
* @param {boolean} [options.keepSessionInfo] - Preserve non-auth session data
336
* @param {Function} callback - Callback function (err) => void
337
*/
338
SessionManager.prototype.logOut = function(req, options, callback);
339
SessionManager.prototype.logOut = function(req, callback); // Options optional
340
```
341
342
**Usage Examples:**
343
344
```javascript
345
const { SessionManager } = require("passport/lib/sessionmanager");
346
347
// Create custom session manager
348
const customManager = new SessionManager(
349
{ key: "auth", keepSessionInfo: true },
350
(user, done) => done(null, user.id)
351
);
352
353
// Or with function as first parameter
354
const simpleManager = new SessionManager((user, done) => {
355
done(null, { id: user.id, role: user.role });
356
});
357
358
// Manual login (typically done through req.logIn)
359
customManager.logIn(req, user, { keepSessionInfo: true }, (err) => {
360
if (err) return next(err);
361
res.redirect("/dashboard");
362
});
363
364
// Manual logout (typically done through req.logOut)
365
customManager.logOut(req, (err) => {
366
if (err) return next(err);
367
res.redirect("/");
368
});
369
```
370
371
## Authentication Info Transformation
372
373
Transform authentication info before it's attached to the request.
374
375
```javascript { .api }
376
/**
377
* Register function to transform auth info with support for multiple signatures
378
* @param {Function} fn - Transform function with flexible arity:
379
* - (info) => transformedInfo (synchronous, arity 1)
380
* - (info, done) => void (asynchronous, arity 2)
381
* - (req, info, done) => void (with request access, arity 3)
382
*/
383
passport.transformAuthInfo(fn);
384
```
385
386
**Usage Examples:**
387
388
```javascript
389
// Synchronous transformation (arity 1)
390
passport.transformAuthInfo((info) => {
391
return {
392
...info,
393
timestamp: new Date().toISOString(),
394
source: "api"
395
};
396
});
397
398
// Asynchronous transformation (arity 2)
399
passport.transformAuthInfo((info, done) => {
400
if (info.clientID) {
401
Client.findById(info.clientID, (err, client) => {
402
if (err) return done(err);
403
info.client = client;
404
done(null, info);
405
});
406
} else {
407
done(null, info);
408
}
409
});
410
411
// Transformation with request access (arity 3)
412
passport.transformAuthInfo((req, info, done) => {
413
const enhanced = {
414
...info,
415
userAgent: req.get("User-Agent"),
416
ip: req.ip,
417
timestamp: new Date().toISOString()
418
};
419
420
// Access user session data if available
421
if (req.session && req.session.preferences) {
422
enhanced.preferences = req.session.preferences;
423
}
424
425
done(null, enhanced);
426
});
427
428
// Use in route handler
429
app.get("/api/profile",
430
passport.authenticate("bearer", { session: false }),
431
(req, res) => {
432
res.json({
433
user: req.user,
434
authInfo: req.authInfo, // Contains transformed info
435
client: req.authInfo.client, // Added by transformer
436
timestamp: req.authInfo.timestamp // Added by transformer
437
});
438
}
439
);
440
```
441
442
## Session Data Structure
443
444
Session data is stored at `req.session[key]` where `key` defaults to `'passport'`:
445
446
```javascript
447
// Session structure
448
req.session.passport = {
449
user: "<serialized user data>"
450
};
451
452
// Example with user ID
453
req.session.passport = {
454
user: "507f1f77bcf86cd799439011"
455
};
456
457
// Example with user object
458
req.session.passport = {
459
user: {
460
id: "507f1f77bcf86cd799439011",
461
role: "admin",
462
lastLogin: "2023-10-15T10:30:00Z"
463
}
464
};
465
```
466
467
## Common Session Patterns
468
469
### Complete Session Setup
470
471
```javascript
472
const express = require("express");
473
const session = require("express-session");
474
const MongoStore = require("connect-mongo");
475
const passport = require("passport");
476
477
const app = express();
478
479
// Session configuration
480
app.use(session({
481
secret: process.env.SESSION_SECRET,
482
resave: false,
483
saveUninitialized: false,
484
store: MongoStore.create({
485
mongoUrl: process.env.MONGODB_URI
486
}),
487
cookie: {
488
secure: process.env.NODE_ENV === "production",
489
maxAge: 24 * 60 * 60 * 1000 // 24 hours
490
}
491
}));
492
493
// Passport configuration
494
app.use(passport.initialize());
495
app.use(passport.session());
496
497
// User serialization
498
passport.serializeUser((user, done) => {
499
done(null, user._id);
500
});
501
502
passport.deserializeUser(async (id, done) => {
503
try {
504
const user = await User.findById(id);
505
done(null, user);
506
} catch (err) {
507
done(err);
508
}
509
});
510
```
511
512
### Session-based Authentication Flow
513
514
```javascript
515
// Login route
516
app.post("/login",
517
passport.authenticate("local", {
518
successRedirect: "/dashboard",
519
failureRedirect: "/login",
520
failureFlash: true
521
})
522
);
523
524
// Protected route
525
app.get("/dashboard", (req, res) => {
526
if (!req.isAuthenticated()) {
527
return res.redirect("/login");
528
}
529
res.render("dashboard", { user: req.user });
530
});
531
532
// Logout route
533
app.post("/logout", (req, res, next) => {
534
req.logOut((err) => {
535
if (err) return next(err);
536
res.redirect("/");
537
});
538
});
539
```
540
541
### API with Mixed Authentication
542
543
```javascript
544
// Session-based web routes
545
app.get("/profile",
546
passport.authenticate("session"),
547
(req, res) => {
548
res.render("profile", { user: req.user });
549
}
550
);
551
552
// Token-based API routes
553
app.get("/api/profile",
554
passport.authenticate("bearer", { session: false }),
555
(req, res) => {
556
res.json(req.user);
557
}
558
);
559
560
// Flexible API endpoint
561
app.get("/api/user",
562
passport.authenticate(["session", "bearer"], { session: false }),
563
(req, res) => {
564
res.json({
565
user: req.user,
566
authMethod: req.authInfo ? "token" : "session"
567
});
568
}
569
);
570
```