Skip to content

Instantly share code, notes, and snippets.

@mietzen
Last active April 26, 2024 17:57
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mietzen/f383d87c0973c1af877b39e09b50021e to your computer and use it in GitHub Desktop.
Save mietzen/f383d87c0973c1af877b39e09b50021e to your computer and use it in GitHub Desktop.
How to use use Bitwarden CLI with macOS Touch ID

How to use Bitwarden CLI with macOS Touch ID

If you want to use Bitwarden CLI for ssh have a look at: How to use use Bitwarden CLI for SSH-Keys in macOS

Wirtten and tested on macOS Ventura

Configure Touch ID for the sudo command

To allow Touch ID on your Mac to authenticate you for sudo access instead of a password you need to do the following.

  • Open Terminal
  • Switch to the root user with: sudo -i
  • Edit /etc/pam.d/sudo:
nano /etc/pam.d/sudo

The contents of this file should look like this:

# sudo: auth account password session
auth       sufficient     pam_smartcard.so
auth       required       pam_opendirectory.so
account    required       pam_permit.so
password   required       pam_deny.so
session    required       pam_permit.so
  • You need to add an additional auth line to the top:

auth sufficient pam_tid.so

  • So it now looks like this:
# sudo: auth account password session
auth       sufficient     pam_tid.so
auth       sufficient     pam_smartcard.so
auth       required       pam_opendirectory.so
account    required       pam_permit.so
password   required       pam_deny.so
session    required       pam_permit.so
  • Save the file with ctrl o and exit with crtl x

  • Try to use sudo, and you should be prompted to authenticate with Touch ID.

Source: https://apple.stackexchange.com/a/306324/409134

Get bw to use Touch ID (via sudo)

  • Add the following line to your .zshrc with: nano ~/.zshrc
export BW_USER='<YOUR-USER>'

bw() {
  bw_exec=$(sh -c "which bw")
  local -r bw_session_file='/var/root/.bitwarden.session' # Only accessible as root

  _read_token_from_file() {

    local -r err_token_not_found="Token not found, please run bw --regenerate-session-key"
    case $1 in
    '--force')
      unset bw_session
      ;;
    esac

    if [ "$bw_session" = "$err_token_not_found" ]; then
      unset bw_session
    fi

    # If the session key env variable is not set, read it from the file
    # if file it not there, ask user to regenerate it

    if [ -z "$bw_session" ]; then
      bw_session="$(
        sh -c "sudo cat $bw_session_file 2> /dev/null"
        # shellcheck disable=SC2181
        if [ "$?" -ne "0" ]; then
          echo "$err_token_not_found"
          sudo -k # De-elevate privileges
          exit 1
        fi
        sudo -k # De-elevate privileges
      )"

      # shellcheck disable=SC2181
      if [ "$bw_session" = "$err_token_not_found" ]; then
        echo "$err_token_not_found"
        return 1
      fi
    fi
  }

  case $1 in
  '--regenerate-session-key')
    echo "Regenerating session key, this has invalidated all existing sessions..."
    sudo rm -f /var/root/.bitwarden.session && ${bw_exec} logout 2>/dev/null # Invalidate all existing sessions

    ${bw_exec} login "${BW_USER}" --raw | sudo tee /var/root/.bitwarden.session &>/dev/null # Generate new session key

    _read_token_from_file --force # Read the new session key for immediate use
    sudo -k                       # De-elevate privileges, only doing this now so _read_token_from_file can resuse the same sudo session
    ;;

  'login' | 'logout' | 'config')
    ${bw_exec} "$@"
    ;;


  '--help' | '-h' | '')
    ${bw_exec} "$@"
    echo "To regenerate your session key type:"
    echo "  bw --regenerate-session-key"
    ;;

  *)
    _read_token_from_file

    ${bw_exec} "$@" --session "$bw_session"
    ;;
  esac
}
  • Then run: exec zsh and bw --regenerate-session-key

If you logout of bitwarden cli again you have to generate a new sessionkey! This might be usefull when traveling internationally.

Now you're good to go! Use with e.g.:

bw get item 99ee88d2-6046-4ea7-92c2-acac464b1412

image

The default sudo timout will be applied (Change sudo timeout)

Edits:

27.08.2023: Updated the help menu, credits to Moulick

10.09.2023: Don't keep elevated rights in Terminal, credits to Moulick

@Moulick
Copy link

Moulick commented Aug 27, 2023

Though I get prompted for touch ID, I still get asked for my master password and 2FA 😢 Is there a way to not have to input master password/2fa everytime?

@mietzen
Copy link
Author

mietzen commented Aug 27, 2023

Though I get prompted for touch ID, I still get asked for my master password and 2FA 😢

Does is ask for Touch ID if you type e.g. sudo ls in terminal?

@Moulick
Copy link

Moulick commented Aug 27, 2023

Nope, once I run --regenerate-session-key in a session, sudo is prompted once but then never again for all other sudo commands

@Moulick
Copy link

Moulick commented Aug 27, 2023

I see that the function above is calling ${bw_exec} logout &> /dev/null, would that not invalidate all sessions and force master password/2fa input everytime?

@Moulick
Copy link

Moulick commented Aug 27, 2023

ah, I completely mis understood the use of the function above. Sorry! Simply running bw list items on a new terminal is prompting me for sudo only, running bw --regenerate-session-key will asks for master password. Which is what you wrote it to do. I thought we had to run --regenerate-session-key in every terminal/script once before bw get item

But absolutely brilliant workaround!! Hats off to you ❤️

@mietzen
Copy link
Author

mietzen commented Aug 27, 2023

ah, I completely mis understood the use of the function above. Sorry! Simply running bw list items on a new terminal is prompting me for sudo only, running bw --regenerate-session-key will asks for master password. Which is what you wrote it to do. I thought we had to run --regenerate-session-key in every terminal/script once before bw get item

I'm glad it worked!

But absolutely brilliant workaround!! Hats off to you ❤️

Thanks ❤️

@Moulick
Copy link

Moulick commented Aug 27, 2023

Cleaned up the function a little, courtesy of shellcheck https://github.com/koalaman/shellcheck, namely quoting to prevent splitting and globing and combining the --help, -h

bw() {
    bw_exec=$(sh -c "which bw")
    case $1 in
    '--regenerate-session-key')
        ${bw_exec} logout &> /dev/null
        ${bw_exec} login "${BW_USER}" --raw | sudo tee /var/root/.bitwarden.session &> /dev/null
        ;;

    '--help'|'-h')
        ${bw_exec} "$@"
        echo "To regenerate your session key type:"
        echo "  bw --regenerate-session-key"
        ;;

    *)
        ${bw_exec} "$@" --session "$(sudo cat /var/root/.bitwarden.session)"
        ;;
    esac
}

@mietzen
Copy link
Author

mietzen commented Aug 27, 2023

Cleaned up the function a little, courtesy of shellcheck https://github.com/koalaman/shellcheck, namely quoting to prevent splitting and globing and combining the --help, -h

bw() {
    bw_exec=$(sh -c "which bw")
    case $1 in
    '--regenerate-session-key')
        ${bw_exec} logout &> /dev/null
        ${bw_exec} login "${BW_USER}" --raw | sudo tee /var/root/.bitwarden.session &> /dev/null
        ;;

    '--help'|'-h')
        ${bw_exec} "$@"
        echo "To regenerate your session key type:"
        echo "  bw --regenerate-session-key"
        ;;

    *)
        ${bw_exec} "$@" --session "$(sudo cat /var/root/.bitwarden.session)"
        ;;
    esac
}

Thanks, I updated the gist 👍

@Moulick
Copy link

Moulick commented Aug 27, 2023

I wonder if there is a way to authorize only bitwarden with sudo. As right now, once you run bw get item and authorize with touchID, the whole terminal gets elevated to sudo :(

@mietzen
Copy link
Author

mietzen commented Aug 27, 2023

bw() {
    bw_exec=$(sh -c "which bw")
    case $1 in
    '--regenerate-session-key')
        ${bw_exec} logout &> /dev/null
        ${bw_exec} login "${BW_USER}" --raw | sudo tee /var/root/.bitwarden.session &> /dev/null
        ;;

    '--help'|'-h')
        ${bw_exec} "$@"
        echo "To regenerate your session key type:"
        echo "  bw --regenerate-session-key"
        ;;

    *)
        ${bw_exec} "$@" --session "$(sudo cat /var/root/.bitwarden.session)"
        ;;
    esac
}

I find no temporary way, only the globally: https://unix.stackexchange.com/questions/382060/change-default-sudo-password-timeout

@Moulick
Copy link

Moulick commented Aug 27, 2023

This now caches the token into an env var rather than reading from the file. Which means we only need to read the file once per session. After read/writing to the file, sudo is revoked with sudo -k. Then I added some error handling for different situations. Now this works in all cases, file missing, env var missing etc.

bw() {
  bw_exec=$(sh -c "which bw")
  local -r bw_session_file='/var/root/.bitwarden.session' # Only accessible as root

  _read_token_from_file() {

    local -r err_token_not_found="Token not found, please run bw --regenerate-session-key"
    case $1 in
    '--force')
      unset bw_session
      ;;
    esac

    if [ "$bw_session" = "$err_token_not_found" ]; then
      unset bw_session
    fi

    # If the session key env variable is not set, read it from the file
    # if file it not there, ask user to regenerate it

    if [ -z "$bw_session" ]; then
      bw_session="$(
        sh -c "sudo cat $bw_session_file 2> /dev/null"
        # shellcheck disable=SC2181
        if [ "$?" -ne "0" ]; then
          echo "$err_token_not_found"
          sudo -k # De-elevate privileges
          exit 1
        fi
        sudo -k # De-elevate privileges
      )"

      # shellcheck disable=SC2181
      if [ "$bw_session" = "$err_token_not_found" ]; then
        echo "$err_token_not_found"
        return 1
      fi
    fi
  }

  case $1 in
  '--regenerate-session-key')
    echo "Regenerating session key, this has invalidated all existing sessions..."
    sudo rm -f /var/root/.bitwarden.session && ${bw_exec} logout 2>/dev/null # Invalidate all existing sessions

    ${bw_exec} login "${BW_USER}" --raw | sudo tee /var/root/.bitwarden.session &>/dev/null # Generate new session key

    _read_token_from_file --force # Read the new session key for immediate use
    sudo -k                       # De-elevate privileges, only doing this now so _read_token_from_file can resuse the same sudo session
    ;;

  '--help' | '-h' | "")
    ${bw_exec} "$@"
    echo "To regenerate your session key type:"
    echo "  bw --regenerate-session-key"
    ;;

  *)
    _read_token_from_file

    ${bw_exec} "$@" --session "$bw_session"
    ;;
  esac
}

@andrzejnovak
Copy link

Thanks a lot! Just to chime in this also works on WSL with https://github.com/nullpo-head/WSL-Hello-sudo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment