Easily switch between many NPM accounts
I maintain a set of Node.js packages using both my personal, and my company’s NPM accounts. I used to check my password manager to switch between them, but turns out there is a much better way.
Auth tokens
When you login, the npm
command-line tool adds a non-expiry authentication
token to $HOME/.npmrc
in a line that looks like this:
//registry.npmjs.org/:_authToken=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
And yes, the auth token is an RFC4122 Universally Unique IDentifier.
The trick here is that .npmrc
can read the authentication token through an
environment variable. For example:
//registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}
So before we continue, login to all your accounts and keep note of the tokens
that npm adds to .npmrc
(I couldn’t find a better way to do this).
Managing profiles
The idea is that we will create a set of environment variables called
NPM_AUTH_TOKEN_
, where you can replace profile
with 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.
Then, we will set NPM_AUTH_TOKEN
, the variable that .npmrc
reads the token
from, to the right value depending on what profile we choose.
But wait. 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 magical shell script I use, which I call npm_run
:
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 afterwards 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. As long as you use it instead of
calling npm
directly, and your shell can access the
NPM_AUTH_TOKEN_
environment variables (if they live in .zshrc
for instance), then everything will just work.
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 do
npm_run RESIN install instead of
npm install`, and so forth.