Profiles·Public

passport-local

semver>=1.0.0postconditions10functions5last verified2026-04-18coverage score83%

Postconditions — what we check

  • Strategy · async-verify-error-handling
    error
    Whenverify callback is async or returns Promise
    ThrowsUnhandledPromiseRejection if async operations not wrapped in try-catch
    Required handlingWhen the verify callback is async or returns a Promise, all async operations (database queries, bcrypt.compare) MUST be wrapped in try-catch. Unhandled promise rejections in the verify callback will crash the Node.js application. Async errors MUST be caught and passed to done(err).
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1]
  • Strategy · verify-callback-done
    error
    Whenverify callback invoked
    ThrowsRequest timeout if done() not called
    Required handlingThe verify callback MUST call the done() callback in all code paths. Patterns: done(err) for server errors, done(null, user) for success, done(null, false) for authentication failures. Not calling done() leaves the request hanging, causing timeouts and resource exhaustion.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[2]
  • Strategy · database-error-propagation
    error
    Whendatabase query fails in verify callback
    ThrowsDatabase error
    Required handlingErrors from database queries (User.findOne, etc.) MUST be checked and propagated to Passport via done(err). Ignoring database errors causes silent failures and incorrect authentication behavior.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[3]
  • Strategy · timing-attack-password-comparison
    warning
    Whenpassword comparison in verify callback
    Returnsboolean indicating password match
    Required handlingPassword comparison SHOULD use constant-time functions like bcrypt.compare() instead of direct string comparison (=== or !==). Direct comparison creates timing side-channel vulnerabilities where attackers can exploit timing differences to guess passwords. CWE-208: Observable Timing Discrepancy.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[4]
  • Strategy · user-enumeration-messages
    warning
    Whenauthentication failure in verify callback
    Returnsdone(null, false, { message })
    Required handlingDifferent error messages for "user not found" vs "wrong password" enable user enumeration attacks. Use the same generic message (e.g., "Invalid credentials") for all authentication failures. CWE-204: Observable Response Discrepancy.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[5]
  • Strategy · authentication-failure-error-type
    warning
    Whenauthentication failure (invalid credentials)
    Returnsdone(null, false)
    Required handlingAuthentication failures MUST return done(null, false), not done(new Error()). Using done(err) for invalid credentials causes HTTP 500 responses instead of proper authentication failure handling (401 or redirect). Reserve done(err) for actual server errors like database connection failures.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[6]
  • Strategy (passReqToCallback) · pass-req-callback-signature-mismatch
    error
    WhenpassReqToCallback: true is set but verify callback uses (username, password, done) signature
    ThrowsRequest hangs (done() never called); timeout after server request timeout
    Required handlingWhen passReqToCallback: true is set, the verify callback MUST use the signature (req, username, password, done) — NOT (username, password, done). With the wrong signature, the req object is silently bound to the username parameter, the actual username to password, and the actual password to done. The real done callback is never called, leaving the HTTP request hanging until the server connection times out. The bug is completely silent — no error is thrown, no warning is logged.
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilitysilent
    Sources[7][8]
  • Strategy (body-parser dependency) · missing-body-parser-silent-400
    error
    Whenbody-parser (express.urlencoded/express.json) middleware not mounted before passport.authenticate()
    ThrowsHTTP 400 'Missing credentials' — not an exception, but an authentication failure
    Required handlingExpress applications using passport-local MUST configure body-parser middleware before calling passport.authenticate(). Without it, req.body is undefined and LocalStrategy returns HTTP 400 'Missing credentials' even when the client sends correct credentials in the POST body. Required middleware order: 1. app.use(express.urlencoded({ extended: false })) // for HTML form submissions 2. app.use(express.json()) // for JSON API clients 3. app.use(passport.initialize()) 4. app.use(passport.session()) 5. app.post('/login', passport.authenticate('local', ...)) This failure produces no server-side error — only the client sees a 400 response. It is a silent misconfiguration that is extremely hard to debug.
    costmediumin prodsilent failureusers seeauthentication failurevisibilitysilent
    Sources[7][2]
  • Strategy (usernameField / passwordField) · field-name-mismatch-silent-400
    warning
    Whenform field names differ from default 'username'/'password' but options not configured
    ThrowsHTTP 400 'Missing credentials' — authentication silently fails
    Required handlingWhen the login form uses non-default field names, LocalStrategy options MUST be explicitly configured to match: new LocalStrategy( { usernameField: 'email', passwordField: 'pass' }, function(email, pass, done) { ... } ) Without this configuration, the strategy looks for req.body.username and req.body.password, finds undefined for both, and returns HTTP 400 'Missing credentials' even though the client sent credentials in the correct field names. The mismatch produces no server-side warning — developers must trace the 400 response back through the strategy source to discover the cause.
    costlowin prodsilent failureusers seeauthentication failurevisibilitysilent
    Sources[7]
  • serializeUser · session-serialization-required
    warning
    Whenusing passport-local with sessions
    ThrowsSession not persisted
    Required handlingUsing passport-local without implementing passport.serializeUser() and passport.deserializeUser() breaks session persistence. Users must re-authenticate on every request. This postcondition does not apply if session support is intentionally disabled (session: false option).
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[2]

Sources

Every postcondition cites at least one of these. Numbered to match the footnotes above.

  1. [1]github.com/jaredhanson/passporthttps://github.com/jaredhanson/passport/issues/536
  2. [2]passportjs.org/concepts/authenticationhttps://www.passportjs.org/concepts/authentication/strategies/
  3. [3]moldstud.com/articles/p-best-practices-for-effective-error-handling-in-passportjshttps://moldstud.com/articles/p-best-practices-for-effective-error-handling-in-passportjs
  4. [4]onlinehashcrack.com/guides/password-recoveryhttps://www.onlinehashcrack.com/guides/password-recovery/timing-attacks-on-password-checks-mitigation-tips.php
  5. [5]onelogin.com/blog/user-enumeration-attacks-what-you-need-to-knowhttps://www.onelogin.com/blog/user-enumeration-attacks-what-you-need-to-know
  6. [6]github.com/jaredhanson/passport-localhttps://github.com/jaredhanson/passport-local/issues/4
  7. [7]github.com/jaredhanson/passport-localhttps://github.com/jaredhanson/passport-local/blob/master/lib/strategy.js
  8. [8]github.com/jaredhanson/passport-localhttps://github.com/jaredhanson/passport-local/issues/128
Need a different package?
Request a profile