npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

npme-auth-foo

v1.0.0

Published

An example auth-strategy for npm Enterprise.

Downloads

3

Readme

Writing Your Own Auth-Plugins for npm Enterprise

npmE launched with authorization that's tightly integrated with GitHub Enterprise:

  • you login to npmE using your GitHub credentials.
  • you can publish modules that correspond to GitHub repos you have write access for.
  • you can install modules that correspond to GitHub repos that you have read access for.

This has been great for companies who use GHE, but overlooks people using other types authorization e.g., LDAP.

In prep for supporting a wider of variety auth-strategies, we're open-sourcing npmE's auth-plugin architecture.

Here's what you need to know to write a custom authentication strategy for npm Enterprise:

Getting Started

An auth-strategy is published as an npm module. Your package should contain the following files:

  • package.json: meta information about the auth-plugin you're building.
  • authenticator.js: the logic for handling user logins.
  • authorizer.js: the logic for handling reading and publishing packages.
  • index.js: the main entry point for a plugin.

index.js

The index.js file is the file loaded by npmE, it should have the following content:

exports.Authenticator = require('./authenticator.js');
exports.Authorizer = require('./authorizer.js');

Writing an Authenticator

An authenticator handles the user's initial login:

npm login --scope=@myregistry --registry=http://my-npmee:8080

The authenticator need only expose the single method authenticate. Here's an example:

function FooAuthenticator() {}

FooAuthenticator.prototype.authenticate = function(credentials, cb) {};

module.exports = FooAuthenticator;

The authenticate method receives a credentials object, and a cb to execute once authentication is complete.

The Credentials Object

The credentials object contains the username, password, and email provided via npm login:

{
  "body": {
    "name": "foo",
    "password": "bar",
    "email": "[email protected]"
  }
}

This login information can then be validated against an arbitrary service, such as your company's LDAP server.

The Callback

If the login fails, execute callback with an error object:

return cb(Error('invalid login'));

If a login is successful it's your responsibility to:

  1. issue a token to associate with the user.
  2. provide a user object to be cached by npmE.
cb(null, {
  token: 'foo-token',
  user: {
    email: credentials.body.email,
    name: credentials.body.name
  }
})

Issuing a Token

The token you issue should be a unique identifier which allows you to associate future installs and publications with the authenticated user. This is the value that will be stored in the user's .npmrc.

In the case of npme-auth-githb, a GitHub application-token is returned. This can be used to authorize future requests against the GitHub API.

Writing an Authorizer

An authorizer handels package installs and publications. To create an authorizer, simply implement the authorize method:

function FooAuthorizer(config) {};

FooAuthorizer.prototype.authorize = function(request, cb) {
};

module.exports = FooAuthorizer;

The authenticate method receives a request object and a cb to execute once authorization is complete.

The Request Object

The request object provided to authorize contains four important pieces of information:

  • request.path: a path representing the package authorization is being performed for.
  • request.method: the type of request being authorized: GET for reads, PUT for publishes.
  • request.body: the package.json contents (this is only sent for publishes).
  • request.headers.authorization: contains the token issued by the authenticator.

The Callback

If an error occurs during authorization, cb should be executed with an error object:

return cb(Error('could not connect to LDAP'));

Otherwise cb should be executed with a true or false value, depending on whether or not authorization is successful:

return cb(null, true); // authorization was successful.

Looking up a Package

The information stored in request.body could potentially contain information that changes package permissions.

In the case of npme-auth-githb, we use the repository field in the package.json to determine who has write permissions for a package. After the initial package publication, the contents of request.body should not be trusted. Instead, you should use request.path to fetch the last version of the package that was published:

FooAuthorizer.prototype.loadPackageJson = function(request, cb) {
  request.get(this.frontDoorHost + request.path.split('?')[0] + '?sharedFetchSecret=' + this.sharedFetchSecret, {
    json: true
  }, function(err, response, package) {
    if (err) return cb(err);
    else return cb(null, response, package);
  });
};

Publishing and Installing Your Auth-Plugin

  1. publish your auth-plugin to npm, with the following naming convention:
  • npme-auth-[my-plugin-name].
  1. edit your npm Enterprise server's configuration to reference the custom plugin:
{
  "args": {
    "--authentication-method": "foo",
    "--authorization-method": "foo",
    "--session-handler": "redis"
  }
}
  1. install your auth-plugin, cd /etc/npme; npm install npme-auth-foo.
  2. regenerate npmE's run-scripts, and restart npme: npme generate-scripts; npme restart.

Some Examples of Auth-Plugins

The example code used in this post is taken from the npme-auth-foo auth-strategy.

For a more thorough working example, check out the npme-auth-github auth strategy. This is default auth approach currently used by npm Enterprise.

That's all you need to know to start writing your own auth-plugins for npm Enterprise!

I can't wait to see what people come up with.