or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-authentication.mdindex.mdsession-management.mdstrategy-development.md

session-management.mddocs/

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

```