Due, presumably, to NPM’s status as an open source provider they don’t make collaborating or using these private packages in your code particularly easy. Even if you add NPM users as collaborators on your private package, they cannot publish or even download the module unless they too have a paid NPM account. Of course all the devs can make sure they’re logged into the Amido account on their machines but this did not work with our automated build and deployments, and I’d like to present a couple of solutions we found to these auth issues.
The first thing we tried was NPM’s recommended method: authentication tokens. Basically when you log in to NPM via the command line on your machine, an ‘.npmrc’ file is generated. This file contains a token which allows you to interact remotely with your NPM account. The great thing about these tokens is they can be shared with other users. By pasting that ‘.npmrc’ file into your project root anyone working on that project will automatically be authorised to run NPM commands against that account.
This worked really well and means that devs can pull down a project repo and install our private packages without getting authorisation errors. The biggest weakness with this, however, was as soon as the user who had generated the token logs out of NPM on his or her machine, that token becomes invalid, making this unreliable as a long term solution.
The next method we attempted was to simply log in to an authorised account on any machine that needed to install the packages. This was fine for devs, albeit clunky, but it wasn’t a great solution for our build processes. For that we needed to automate the login and NPM provide no easy way to immediately pass your credentials into the login command. We managed to get round this with the following snippet:
npm login << EOF
This was still a little clunky so we bundled the credentials into a text file stored in the app root and piped this file into the command like so:
npm login < auth.txt
While this seemed a little cleaner there were still several issues. Firstly, hardcoding credentials into our source code seemed a little hacky. Secondly, while running it in Bash was fine, Powershell had issues with the syntax. And thirdly, running it via our automated build process (in this case, an Appveyor container without STDIN open), threw an NPM callback error.
It was pretty clear that the first option was the best but the temporary token issue made it extremely fragile. Fortunately, we found a fairly simple workaround – simply login into NPM to generate the token, copy it into your project and then delete the token from your machine. This way you erase all traces of the session and running ‘npm logout’ will not destroy the token. The only way to delete it at that point is by logging into your NPM account manually and destroying the token there. This step made the solution far more robust and was the one that we settled on.
Of course both these issues have one flaw – we are bundling security credentials, be it login details or security token, in our repo. In the case that spawned this blog post it is not really a concern as both the NPM package and the project that consumed it were contained in private repos. If, however, your project is stored in a public repo you will probably want to come up with a way to encrypt these bundled credentials. Perhaps we’ll address this issue in a follow up post…