mrkeyoor.com_
Sat 19 Sept 15:53 UTC
npmSecurityupdated 18 Sept 2026

passport review

Passport 0.7.0 is Express and Connect middleware that runs a named authentication strategy, places the resulting principal on the request, and optionally links that identity to a server-side login session. The core does not hash passwords, issue tokens, create users, define routes, or decide authorization. Those jobs belong to application code and separately installed strategies. The 0.7.0 change makes `assignProperty` authentication populate `req.authInfo` by default unless `authInfo` is disabled. Our package check found a small CommonJS server module with no bundled types.

Verdict

passport 0.7.0 installed in 1.3 seconds and occupied 1 MB in our sandbox, but that tiny core includes neither TypeScript declarations nor the account and policy layers required for a finished login system. Keep it for Express apps that benefit from interchangeable strategies; choose a fuller auth system for new products that want those missing pieces together.

We installed it

Lab card: what happened when we installed passportScreenshot of passport documentation
Install✓ · 1.3s4 packages on disk · 1 MB
ImportESM import works · require() works · CommonJS package
Browsern/acould not be bundled for the browser (Node-only code, most likely)
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does passport install cleanly?

Yes. In a fresh container with an empty cache, npm install passport finished in 1 seconds, leaving 4 packages and 1 MB on disk. npm audit reported no known vulnerabilities.

Can passport run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does passport work with both ESM and CommonJS?

Yes. Both import 'passport' and require('passport') worked in Node 22 in our run. The package is published as CommonJS.

Does passport include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

passport or better-auth: which should you use?

better-auth: Choose it for a TypeScript-oriented system that includes sessions, account flows, adapters, and plugins. passport 0.7.0 installed in 1.3 seconds and occupied 1 MB in our sandbox, but that tiny core includes neither TypeScript declarations nor the account and policy layers required for a finished login system.

When should you not use passport?

Passport is not an identity product. It provides no registration, password reset, MFA enrollment, account UI, or user database.

API stability4/5Passport's strategy contract, `authenticate()` middleware, `req.user`, and serialization callbacks have stayed recognizable for many years. Version 0.6 changed login and logout to regenerate sessions and use callbacks, while 0.7.0 adjusted `authInfo` when `assignProperty` is used. The package remains below 1.0, but its slow release pace means established applications rarely face frequent migration work.
Docs3/5The Passport site explains strategies, sessions, middleware order, route authentication, redirects, and custom callbacks, with examples for common providers. The core model is easy to follow. Some repository examples and linked tutorials use old Express conventions, while production topics such as proxy-aware cookies, CSRF, durable session stores, and provider-specific state are spread across other packages and sites.
Maintenance3/5The npm package remains on version 0.7.0, and GitHub records the repository's last push on August 16, 2024. The repository is not archived and has 23,533 stars, but GitHub also shows 398 open issues and pull requests. A mature core can change slowly; security reviews still must examine each chosen strategy because core activity says nothing about that plugin's maintenance.
Ecosystem5/5npm recorded 8,144,319 Passport downloads from August 19 through August 25, 2026, and GitHub reports 23,533 stars. Its strategy convention covers passwords, bearer tokens, JWT, social OAuth, OpenID Connect, SAML, and custom schemes. The catalog is the main reason to use Passport, although independently maintained strategies vary widely in protocol support, types, and release health.

Use it if

  • An Express application needs local login, OAuth, OpenID Connect, SAML, JWT, or another strategy behind one request convention.
  • The application should own user records, routes, redirects, session data, and failure responses while a strategy handles protocol verification.
  • You are maintaining an existing Passport system and want to keep its established `req.user` and `authenticate()` integration.
  • Browser login needs server-side sessions and you can provide explicit serialization and deserialization callbacks.
Skip it if

Setup reality

Our install of passport 0.7.0 finished in 1.3 seconds in a fresh Node 22 Bookworm container. It left 4 packages and 1 MB on disk, and npm audit reported 0 vulnerabilities at every severity. Passport declares 3 direct dependencies and 0 peers, with 240 KB unpacked. It is an MIT-licensed CommonJS package without an exports map. require() and ESM import both worked, but the package contains no TypeScript declarations.

The core cannot verify a password or OAuth response alone. Add a strategy, register it with passport.use(), and decide how failure reaches the client. Session login also needs express-session mounted before passport.initialize() and passport.session(). Serialize a stable user identifier, then load the current user during deserialization. Session persistence, expiry, and storage are owned by the session middleware and its store, not by Passport 0.7.0.

Current Passport regenerates a session on login and logout to reduce fixation risk. keepSessionInfo copies existing session values into the new session, which is useful for a cart but unsafe as a casual default. req.logout() requires a callback. Provider strategies also need exact callback URLs, state handling, secrets, and correct HTTPS proxy settings. A provider rejecting the callback URI is usually a registration mismatch rather than a route-order problem.

No TypeScript types were present in our measured package; @types/passport supplies request augmentation separately, and strategies may need additional declarations. The package could not be bundled for a browser with esbuild, consistent with its Node-only middleware role. For JSON endpoints, use a custom authentication callback instead of redirects, and call req.logIn() yourself if that branch should create a session. Add rate limits, CSRF defenses, authorization checks, and account policy outside Passport.

Patterns

Put session state before Passport mount-session-middleware

const session = require('express-session');
const passport = require('passport');

app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  store: sessionStore,
  cookie: { httpOnly: true, sameSite: 'lax', secure: true },
}));
app.use(passport.initialize());
app.use(passport.session());

Use a persistent store outside development. Secure cookies also depend on correct HTTPS termination and Express proxy settings.

Check a username and password verify-password

const LocalStrategy = require('passport-local');

passport.use(new LocalStrategy(async (username, password, done) => {
  try {
    const user = await User.findOne({ username });
    if (!user || !(await verifyPassword(user, password))) return done(null, false);
    return done(null, user);
  } catch (error) {
    return done(error);
  }
}));

Password hashing, throttling, lockout rules, and neutral error text stay in application code rather than `passport-local`.

Keep only an identifier in the session store-session-user

passport.serializeUser((user, done) => done(null, user.id));
passport.deserializeUser(async (id, done) => {
  try {
    done(null, await User.findById(id));
  } catch (error) {
    done(error);
  }
});

Deserialization can query the database for every authenticated request, so fetch only fields downstream handlers need.

Redirect after form authentication login-with-redirect

app.post('/login', passport.authenticate('local', {
  successRedirect: '/account',
  failureRedirect: '/login',
}));

Redirect responses suit browser forms. An API client usually needs a custom callback and an explicit JSON status.

Return a JSON login response login-json-api

app.post('/api/login', (req, res, next) => {
  passport.authenticate('local', (error, user, info) => {
    if (error) return next(error);
    if (!user) return res.status(401).json({ error: 'invalid credentials' });
    req.logIn(user, (loginError) => {
      if (loginError) return next(loginError);
      res.json({ id: user.id });
    });
  })(req, res, next);
});

The custom callback owns success and failure. Call `req.logIn()` when successful authentication should persist a session.

Reject requests without a session user protect-route

function requireUser(req, res, next) {
  if (req.isAuthenticated()) return next();
  return res.status(401).json({ error: 'authentication required' });
}

app.get('/api/account', requireUser, (req, res) => res.json(req.user));

This middleware checks identity only. Tenant, role, and resource-ownership decisions need a separate policy layer.

End the login session logout-session

app.post('/logout', (req, res, next) => {
  req.logout((error) => {
    if (error) return next(error);
    req.session.destroy((destroyError) => {
      if (destroyError) return next(destroyError);
      res.clearCookie('connect.sid');
      res.sendStatus(204);
    });
  });
});

`req.logout()` is asynchronous in current Passport. Destroying application session data and clearing its cookie are additional operations.

Verify a bearer token without a session authenticate-jwt

const { Strategy: JwtStrategy, ExtractJwt } = require('passport-jwt');

passport.use(new JwtStrategy({
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
  secretOrKey: process.env.JWT_SECRET,
}, (payload, done) => done(null, { id: payload.sub })));

app.get('/api/me', passport.authenticate('jwt', { session: false }), handler);

Production validation should pin algorithms and check issuer, audience, expiry, and key rotation; one shared secret is rarely the whole policy.

Wire an OAuth redirect and callback start-oauth

app.get('/auth/google', passport.authenticate('google', { scope: ['openid', 'email', 'profile'] }));
app.get('/auth/google/callback',
  passport.authenticate('google', { failureRedirect: '/login' }),
  (req, res) => res.redirect('/account')
);

Register the exact HTTPS callback URL with the provider, then review whether the chosen strategy supports state and PKCE as required.

Carry selected state through login preserve-cart-session

app.post('/login', passport.authenticate('local', {
  successRedirect: '/checkout',
  failureRedirect: '/login',
  keepSessionInfo: true,
}));

`keepSessionInfo` retains pre-login values after session regeneration. Leave it off when untrusted session data should be discarded.

Alternatives

PackageRegistryPick it when
better-authnpmChoose it for a TypeScript-oriented system that includes sessions, account flows, adapters, and plugins.
@auth/expressnpmChoose Auth.js when provider configuration and its Express integration cover the required sign-in flows.
openid-clientnpmChoose it when OpenID Connect and OAuth protocol control matters more than a shared strategy abstraction.

More security guides

cryptography · pyjwt · jose · dompurify · requests-oauthlib · jsonwebtoken · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.