Passport HTTP Basic and Digest Strategies
raw JSON →Passport-HTTP-2 provides HTTP Basic and Digest authentication strategies for Passport.js, enabling stateless authentication for Node.js applications that support Connect-style middleware like Express. Currently at version 1.1.1, the library's release cadence appears to be on-demand, with the last notable update in 2019 and last commit in 2022, suggesting a maintenance rather than actively developed status. It serves as a fork of the original `jaredhanson/passport-http` module, which itself is less actively maintained. This fork aims to offer continued support for these fundamental HTTP authentication schemes, often used for protecting API endpoints where sessions are not desired. Developers leverage this module to integrate standard basic (username/password over plaintext, requires HTTPS) and digest (challenge-response, avoids cleartext password) authentication into their Passport-based applications.
Common errors
error TypeError: BasicStrategy is not a constructor ↓
import { BasicStrategy } from 'passport-http-2';. For CommonJS, ensure const { BasicStrategy } = require('passport-http-2'); or const BasicStrategy = require('passport-http-2').BasicStrategy; if it's not a direct named export. error Error: Unknown authentication strategy "basic" ↓
passport.use(new BasicStrategy(...)) (or DigestStrategy) is called to configure and register the strategy before any routes attempt to use passport.authenticate('basic', ...). error 401 Unauthorized (without credential prompt) ↓
verify/secret callback logic to ensure it correctly identifies valid users and passwords. Also, check browser/client cache, especially in development, as browsers might cache HTTP auth credentials. error RangeError: Invalid digest parameter 'qop' ↓
qop option in new DigestStrategy({ qop: 'auth' }, ...) is correctly set to a valid string like 'auth' or 'auth-int' as per RFC 2617. Warnings
gotcha As a fork of `passport-http`, be aware that `passport-http-2` might introduce subtle behavioral differences or have a different maintenance schedule. Always consult the specific documentation for this fork. ↓
breaking HTTP Basic authentication transmits credentials in plain text. It is critically important to use HTTPS in production environments to prevent eavesdropping and credential theft. ↓
gotcha Forgetting to set `session: false` in `passport.authenticate()` when using HTTP Basic or Digest strategies will cause Passport to attempt to establish a login session. This is often undesired for stateless API authentication and can lead to unexpected behavior or errors if session middleware is not configured. ↓
gotcha The `done` callback in Passport strategies has a specific signature: `done(err, user, info)`. Incorrectly passing parameters (e.g., `done(user)` instead of `done(null, user)`) can lead to authentication failures or server errors. ↓
gotcha The `DigestStrategy`'s `secret` callback (for retrieving the user's password/secret from the database) has a different signature than `BasicStrategy`'s `verify` callback. It expects `done(err, user, password)`, providing the actual server-side password for hash computation, unlike Basic which just needs `done(err, user)`. ↓
Install
npm install passport-http-2 yarn add passport-http-2 pnpm add passport-http-2 Imports
- BasicStrategy wrong
const BasicStrategy = require('passport-http-2').BasicStrategy;correctimport { BasicStrategy } from 'passport-http-2'; - DigestStrategy wrong
const DigestStrategy = require('passport-http-2').DigestStrategy;correctimport { DigestStrategy } from 'passport-http-2'; - passport wrong
import { passport } from 'passport';correctimport passport from 'passport';
Quickstart
import express from 'express';
import passport from 'passport';
import { BasicStrategy, DigestStrategy } from 'passport-http-2';
const app = express();
// In a real application, replace this with a database or secure user store
const users = new Map<string, { password?: string, digestSecret?: string, id: string }>([
['alice', { password: 'password', id: 'alice' }],
['bob', { digestSecret: 'secret', id: 'bob' }]
]);
passport.use(new BasicStrategy(
async (userid, password, done) => {
console.log(`Basic attempt for user: ${userid}`);
const user = users.get(userid);
if (!user || user.password !== password) {
return done(null, false); // Authentication failed
}
return done(null, user); // Authentication successful
}
));
passport.use(new DigestStrategy(
{ qop: 'auth' }, // Quality of Protection (qop) for Digest authentication
async (username, done) => {
console.log(`Digest attempt for user: ${username}`);
const user = users.get(username);
if (!user) {
return done(null, false); // User not found
}
// Digest strategy expects user, then the shared secret (password)
return done(null, user, user.digestSecret);
},
async (params, done) => {
// Optional: Validate nonce-related parameters here to prevent replay attacks
// For this example, we just say 'true'
console.log('Digest nonce params:', params);
done(null, true);
}
));
app.use(passport.initialize());
app.get('/', (req, res) => {
res.send('Hello, you can try accessing /basic or /digest');
});
app.get('/basic', passport.authenticate('basic', { session: false }), (req, res) => {
res.json({ message: `Hello Basic authenticated user: ${(req.user as any).id}` });
});
app.get('/digest', passport.authenticate('digest', { session: false }), (req, res) => {
res.json({ message: `Hello Digest authenticated user: ${(req.user as any).id}` });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
console.log('Try: curl -u alice:password http://localhost:3000/basic');
console.log('Try: curl --digest -u bob:secret http://localhost:3000/digest');
});