Passport strategy for authenticating an npm
client.
const { NPMStrategy, NPMStrategyErrorHandler } = require('passport-npm');
// check the login of a user and create a user object
// set user to `false` if login is invalid
function authenticate({
req, // HTTP.IncomingMessage
name, // string
password // string
}, done) {
done(null, /* User on success || false on failure */);
}
// creates a string for `npm` to store in user .npmrc
// send a falsey string to not use tokens (not recommended)
//
// use this to prevent `npm` from storing username and password on disk
// commonly used to store an access token
function serializeNPMToken({
req, // HTTP.IncomingMessage
name, // string
password // string
}, done) {
done(null, /* non-falsey token string || false to store username and password instead */)
}
// similar to `authenticate`
//
// consumes the result token string serializeToken
function deserializeNPMToken({
req, // HTTP.IncomingMessage
token // string
}, done) {
done(null, /* User on success || false on failure */);
}
passport.use(new NPMStrategy({
// router needs to support router.put(...middleware)
// registers PUT: /-/user/org.couchdb.user:*
router, // optional
authenticate,
serializeNPMToken,
deserializeNPMToken
}));
router.get('/privileged',
passport.initialize(),
passport.authenticate('npm', {
// npm client doesn't have compatible sessions with PassportJS
// - does not use a cookie
// - uses bearer tokens and basic auth via HTTP authorization header
session: false,
// npm client doesn't have compatible response parsing with PassportJS
// error.status will be the expected status code of the error
// NOTE: `npm` does not like status codes that are not:
// 200, 201, 400, 401, 403, or 500
failWithError: true
}),
// function to convert responses so npm client understands them
NPMStrategyErrorHandler
...
);
In your project repositories wishing to connect to the npm
authenticated server place a local $PROJECT/.npmrc
file with:
registry=http://path.to.server.local:1337/
always-auth=true
Then run npm login
to put your authentication information in your user configuration at ~/.npmrc
.
This will keep your login information outside of your project.
npm
uses the authorization:
HTTP header and bearer tokens instead of Cookies. Passport only supports cookie based sessions normally. They are not named [de]serializeUser
to avoid confusion with passport based sessions.
This is required so that users can use npm login
against your router. It is optional, but recommended if you support basic auth.
npm
expects a JSON response for failed logins, Passport sends back plaintext. This middleware will correct errors to a format npm
understands and stop propagating the error. It expects error.status
be the expected status code and error.message
to be a message (Note: the npm
cli often ignores custom messages).
Not recommended, but:
- mandate
always-auth=true
for yournpm
configuration - ensure your
~/.npmrc
has login (_auth
andemail
) information entered in it properly. - create a
deserializeToken
method that always generates an falsey user - you must still have
serializeToken
successfully generate a falsey token (it will be thrown away after authentication)
- Manually add your
_authToken
to your.npmrc
file with syntax like:
//my.registry.invalid/:_authToken="string to pass to deserializeToken"
- create a
authenticate
method that always generates a falsey user. - create a
serializeToken
method that always generates an Error.
# startup
PORT=8080 node example.js
npm login --registry=http://localhost:8080/
# username = user
# password = pass
# email = # ignored
npm --registry=http://localhost:8080/ install passport-npm
Correct, this is a feature of the npm
client and not related to passport-npm
.
This is most likely caused by your ~/.npmrc
user config having authentication information in it. Try npm logout
then npm login
.
Currently, we cannot reliably setup configuration for yarn
due lacking options that match the npm
client to perform integration tests. It does appear to work though at least naively.