Search code examples
npmnpm-registry

How do we verify "npm login" succeeded and the token has not expired?


I've got a script that verifies a user has logged into a private npm registry (via "npm login") by greping for:

//registry-sub-url:_authToken=

... in:

~/.npmrc

However, this breaks down over time as the user's credentials expire (due to standard password expiration rules).

What's more, the helper scripts I've created have cannot differentiate between successful/failed npm login calls, since the script always exits with 0 status.

Q: (1) How do we verify that npm login succeeded? (2) How do identify when the npm token has expired?


Solution

  • I'm posting the workaround I came up with, but I'd love a better solution.

    I've got Jenkins running this bash script periodically to test/verify my npm login against a private registry:

    #/bin/bash
    
    # Suppress commands (Jenkins turns this on)
    set +x
    
    # Suppress color codes from NPM output (for proper grepping)
    export TERM=dumb
    
    # Stop on any error
    set -e
    
    NPM_USERNAME=...
    NPM_PASSWORD=...
    NPM_URL=...
    NPM_EMAIL=...
    WORKSPACE=... (in my case, set by Jenkins)
    
    echo "========"
    echo "Looking for previous failed login (cached credentials)..."
    echo ""
    # NOTE: A previous failed login can result in an ".npmrc" containing
    # a username/password in lieu of an auth token. We look for this and
    # remove it (logout) if it exists so that the cached credentials are
    # not applied when we run "expect" to login
    # (which would see different prompts from cached credentials).
    
    # Chop off "http:"/"https:" prefix from URL
    NPM_REPO_PREFIX=`sed -e 's~https\{0,1\}:\(.*\)~\1~' <<< "$NPM_URL"`
    
    # NOTE: piping to /dev/null so the password isn't printed
    set +e
    grep -F "${NPM_REPO_PREFIX}:_password=" ~/.npmrc > /dev/null
    GREP_EXIT="$?"
    set -e
    
    if [[ "$GREP_EXIT" == "0" ]]; then
        echo "========"
        echo "Logging out of repo..."
        echo ""
    
    
        npm logout --registry "$NPM_URL"
    fi
    
    echo "========"
    echo "Logging into repo..."
    echo ""
    
    (/usr/bin/expect <<EOF
    set timeout 10
    spawn npm login --verbose --registry "$NPM_URL"
    match_max 100000
    
    expect "Username"
    send "$NPM_USERNAME\r"
    
    expect "Password"
    send "$NPM_PASSWORD\r"
    
    expect "Email"
    send "$NPM_EMAIL\r"
    
    expect {
       timeout      exit 1
       expect eof
    }
    
    EOF
    ) | tee "$WORKSPACE/npm-login.out"
    
    echo "========"
    echo "Verifying output of login..."
    echo ""
    # NOTE: If the login fails, the npm command still exits with status "0",
    # so we read the verbose output to see that the http server confirms
    # successful with "http 201".
    
    set +e
    grep "npm http 201" "$WORKSPACE/npm-login.out"
    GREP_EXIT="$?"
    set -e
    
    if [[ "$GREP_EXIT" != "0" ]]; then
      >&2 echo "========"
      >&2 echo "ERROR: Failed to login to repo [$NPM_REPO]"
      exit 1
    else
      echo "========"
      echo "SUCCESS: Logged into [$NPM_REPO]"
    fi