Easily switch between many NPM accounts


TL;DR: This article describes a trick for easily switching between multiple NPM accounts on the terminal

I maintain Node.js packages using my personal and my company’s NPM accounts. I used to rely on my password manager to switch between them using npm login, but it turns out there is a much better way.

Auth tokens

When you log in, the npm command-line tool adds a non-expiry authentication token to $HOME/.npmrc as a line that looks like this:

//registry.npmjs.org/:_authToken=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

The auth token is an UUID.

The trick is that .npmrc can read the authentication token through an environment variable. For example:

//registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}

Before we continue, log in to all your accounts and keep a note of the tokens that npm adds to .npmrc (I couldn’t find a better way to do this).

Managing profiles

We will create a set of environment variables that look like: NPM_AUTH_TOKEN_{{profile}}, where profile stands for any descriptive name you can come up with. I have NPM_AUTH_TOKEN_PERSONAL and NPM_AUTH_TOKEN_RESIN, since I work at resin.io.

The idea is to set NPM_AUTH_TOKEN, the variable that .npmrc reads the token from, to the right value depending on what profile we choose. However, environment variables are defined on a per-process basis, so how are we going to “update” the variable npm will read?

Shell scripts FTW

This is the shell script I use, which I call npm_run:

#!/bin/zsh

set -u
set -e

if [ "$#" -lt 2 ]; then
  echo "Usage: $0 <profile> <command...>" 1>&2
  exit 1
fi

# Transform to uppercase
# See http://stackoverflow.com/a/11392235/1641422
ARGV_PROFILE=$(echo "$1" | tr '[:lower:]' '[:upper:]')

TOKEN_ENVIRONMENT_VARIABLE="NPM_AUTH_TOKEN_$ARGV_PROFILE"

# We need to check the variable exists before attempting
# to blindly expand it afterward to avoid shell errors
if ! set | grep --text "^$TOKEN_ENVIRONMENT_VARIABLE" >/dev/null; then
  echo "Unknown profile: $ARGV_PROFILE"
  exit 1
fi

echo "Loading profile $ARGV_PROFILE..."

# Dynamically expand variable
# See http://unix.stackexchange.com/a/251896/43448
export NPM_AUTH_TOKEN=$(print -rl -- ${(P)TOKEN_ENVIRONMENT_VARIABLE})

echo "Logged in as $(npm whoami)"
npm ${@:2}

This script takes a profile and a set of npm command arguments and will call npm with the right authentication token.

It will all work as long as you run the script instead of calling npm directly, and your shell can access the NPM_AUTH_TOKEN_{{profile}} environment variables (if they live in .zshrc for instance)

With this script, I can easily publish a package using my personal account by running npm_run PERSONAL publish instead of npm publish. If I need to install dependencies from private npm packages owned by my company, I can run npm_run RESIN install instead of npm install, and so forth.