Auto-Loading Bitwarden Secrets as Environment Variables in Zsh

This post showcases a Zsh script that auto-refreshes Bitwarden sessions and exports secrets as environment variables.

Usage

  1. Save the script as ~/.oh-my-zsh/custom/bw-session.zsh.
  2. Ensure bitwarden-cli, jq, and the macOS security utility are installed.
  3. Adjust BW_ENV_MAPPING for each ENV_VAR → "item-id#selector".
  4. set_secrets when you need tokens

Final Script

# ~/.oh-my-zsh/custom/bw-session.zsh
# ——————————————————————————————————————————————
set +x
emulate -L zsh

### CONFIGURATION ###
: "${BW_KEYCHAIN_SERVICE:=bitwarden-master}"   # your master-pwd keychain entry
: "${BW_EMAIL:=you@example.com}"

# ENV_VAR → "item-id#selector" (notes|password|username|totp|field:<name>)
typeset -A BW_ENV_MAPPING=(
  GREENPT_API_KEY "fc92e0c4-2b60-452a-8fb9-b3090150ae86#notes"
  SUPADATA_API_KEY "c0e2a7b0-444b-4d97-a05b-b32b014f216d#notes"
)

### SESSION MANAGEMENT (in-memory only) ###
_bw_read_master() {
  security find-generic-password -s "$BW_KEYCHAIN_SERVICE" -w 2>/dev/null
}

_bw_setup_session() {
  # if already set and works, reuse
  if [[ -n $BW_SESSION ]]; then # && bw get item "${(k)BW_ENV_MAPPING}[1]" --session "$BW_SESSION" &>/dev/null; then
    return 0
  fi

  # fetch master password
  local _pw; _pw=$(_bw_read_master) || return 1

  # unlock (or login if first time)
  if [[ "$(bw status --raw)" == *\"locked\"* ]]; then
    BW_SESSION=$(env BW_MASTER="$_pw" \
      bw unlock --passwordenv BW_MASTER --raw) || return 1
  else
    BW_SESSION=$(env BW_MASTER="$_pw" \
      bw login "$BW_EMAIL" \
        --passwordenv BW_MASTER --raw) || return 1
  fi
  unset _pw
  export BW_SESSION
  bw sync --session "$BW_SESSION" &>/dev/null || true
}

### FETCH & EXPORT ###
_bw_fetch_and_export() {
  local var spec item sel json val
  for var in "${(@k)BW_ENV_MAPPING}"; do
    spec=${BW_ENV_MAPPING[$var]}
    item=${spec%%#*}; sel=${spec#*#}

    json=$(bw get item "$item" --session "$BW_SESSION")

    case $sel in
      notes)    val=$(print -r -- "$json" | jq -r .notes) ;;
      password) val=$(print -r -- "$json" | jq -r .login.password) ;;
      username) val=$(print -r -- "$json" | jq -r .login.username) ;;
      totp)     val=$(bw get totp "$item" --session "$BW_SESSION") ;;
      field:*)  val=$(print -r -- "$json" \
                     | jq -r --arg n "${sel#field:}" \
                       '(.fields//[] | select(.name==$n) | .value)') ;;
    esac

    [[ -n $val ]] && export "$var=$val"
  done
}

function set_secrets() {
  _bw_setup_session && _bw_fetch_and_export
}