--- layout: docs page_title: Use a custom token helper description: >- The Vault CLI supports external token helpers to help simplify retrieving, setting and erasing authentication tokens. --- # Use a custom token helper A **token helper** is a program or script that saves, retrieves, or erases a saved authentication token. By default, the Vault CLI includes a token helper that caches tokens from any enabled authentication backend in a `~/.vault-token` file. You can customize the caching behavior with a custom token helper. ## Step 1: Script your helper Your token helper must accept a single command-line argument: Argument | Action -------- | ------ `get` | Fetch and print a cached authentication token to `stdout` `store` | Read an authentication token from `stdin` and save it in a secure location `erase` | Delete a cached authentication token You can manage the authentication tokens in whatever way you prefer, but your helper must adhere to following output requirements: - Limit `stdout` writes to token strings. - Write all error messages to `stderr`. - Write all non-error and non-token output to `syslog` or a log file. - Return the status code `0` on success. - Return non-zero status codes for errors. ## Step 2: Configure Vault To configure a custom token helper, edit (or create) a CLI configuration file called `.vault` under your home directory and set the `token_helper` parameter with the **fully qualified path** to your new helper: ``` echo 'token_helper = "/path/to/token/helper.sh"' >> ${HOME}/.vault ``` Make sure to use UTF-8 encoding (`ascii`) or Vault may complain about invalid characters when reading the configuration file: ```powershell 'token_helper = "\\path\\to\\token\\helper.ps1"' | ` Out-File -FilePath ${env:USERPROFILE}/.vault -Encoding ascii -Append ``` Make sure the script is executable by the Vault binary. ## Example token helper The following token helper manages tokens in a JSON file in the home directory called `.vault_tokens`. The helper relies on the `$VAULT_ADDR` environment variable to store and retrieve tokens from different Vault servers. ```shell-session #!/bin/bash function write_error(){ >&2 echo $@; } # Customize the hash key for tokens. Currently, we remove the strings # 'https://', '.', and ':' from the passed address (Vault address environment # by default) because jq has trouble with special characeters in JSON field # names function createHashKey { local key="" if [[ -z "${1}" ]] ; then key="${VAULT_ADDR}" else key="${1}" fi # We index the token according to the Vault server address by default so # return an error if the address is empty if [[ -z "${key}" ]] ; then write_error "Error: VAULT_ADDR environment variable unset." exit 100 fi key=${key//"http://"/""} key=${key//"."/"_"} key=${key//":"/"_"} echo "addr-${key}" } TOKEN_FILE="${HOME}/.vault_token" KEY=$(createHashKey) TOKEN="null" # If the token file does not exist, create it if [ ! -f ${TOKEN_FILE} ] ; then echo "{}" > ${TOKEN_FILE} fi case "${1}" in "get") # Read the current JSON data and pull the token associated with ${KEY} TOKEN=$(cat ${TOKEN_FILE} | jq --arg key "${KEY}" -r '.[$key]') # If the token != to the string "null", print the token to stdout # jq returns "null" if the key was not found in the JSON data if [ ! "${TOKEN}" == "null" ] ; then echo "${TOKEN}" fi exit 0 ;; "store") # Get the token from stdin read TOKEN # Read the current JSON data and add a new entry JSON=$( jq \ --arg key "${KEY}" \ --arg token "${TOKEN}" \ '.[$key] = $token' ${TOKEN_FILE} ) ;; "erase") # Read the current JSON data and remove the entry if it exists JSON=$( jq \ --arg key "${KEY}" \ --arg token "${TOKEN}" \ 'del(.[$key])' ${TOKEN_FILE} ) ;; *) # change to stderr for real code write_error "Error: Provide a valid command: get, store, or erase." exit 101 esac # Update the JSON file and return success echo $JSON | jq "." > ${TOKEN_FILE} exit 0 ``` ```powershell <# .Synopsis Vault token helper script .INPUTS Positional/command line argument: get, store, erase .OUTPUTS get: prints a cached authentication token to stdin (if it exists) store: no output, updates the token cache erase: no output, updates the token cache #> <# .Synopsis CreateHashKey .DESCRIPTION Customize the hash key for tokens. Currently, we remove the strings 'https://', '.', and ':' from the passed address (Vault address environment by default) variable to simplify the hash key string #> function CreateHashKey { Param($address = "${env:VAULT_ADDR}") # We index the token according to the Vault server address by default so # return an error if the address is empty if ( -not $address) { Write-Error "[Missing value] env:VAULT_ADDR currently unset." exit 101 } $key = ${address}.Replace("/","").Replace(".","_").Replace(":","_") return ${key}.Replace("http_", "addr-") } <# .Synopsis GetTokenCache .DESCRIPTION Read in or create a new token cache and initialize the hash #> function GetTokenCache { Param($filename) # Read the JSON file (token cache) and initialize the hash data or create an # empty hash if the file does not exist yet if ( Get-Item -Path "./${filename}" -ErrorAction SilentlyContinue ) { $fileData = (Get-Content "${filename}" -Raw | ConvertFrom-Json -AsHashtable) } else { $fileData = (Write-Output "{}" | ConvertFrom-Json -AsHashtable) } return $fileData } <# .Synopsis UpdateTokenCache .DESCRIPTION Write the token hash out to the cache #> function UpdateTokenCache { Param($filename, $fileData) $jsonData = ($fileData | ConvertTo-Json) # Convert the hash to JSON and update the token cache $jsonData | Out-File -Encoding ascii "${filename}" return } $tokenFile = "${env:USERPROFILE}/.vault_token" $hashData = (GetTokenCache "${tokenFile}") $key = (CreateHashKey) $token = $null switch -Exact -CaseSensitive (${args}[0]) { "get" { # Print the token to stdin and return success Write-Output ${hashData}.${key} exit 0 } "store" { $token = Read-Host # Add the new token to the hash $hashData["${key}"] = "${token}" } "erase" { # Erase the token entry if it exists if ($hashData.ContainsKey("${key}") ) { $hashData.Remove("${key}") } } Default { # The argument was invalid so return an error Write-Error "[Invalid argument] Command must be: get, store, or erase." exit 102 } } # Update the token cache and return success UpdateTokenCache ${tokenFile} ${hashData} exit 0 ``` ```ruby #!/usr/bin/env ruby require 'json' // We index the token according to the Vault server address // so the VAULT_ADDR variable is required unless ENV['VAULT_ADDR'] STDERR.puts "No VAULT_ADDR environment variable set. Set it and run me again!" exit 100 end // If the token file does not exist, create and initialize the hashmap begin tokens = JSON.parse(File.read("#{ENV['HOME']}/.vault_tokens")) rescue Errno::ENOENT => e # file doesn't exist so create a blank hash for it tokens = {} end // Get the first command line argument case ARGV.first when 'get' // Write the token to stdout if it exists print tokens[ENV['VAULT_ADDR']] if tokens[ENV['VAULT_ADDR']] exit 0 when 'store' // Read the token from stdin tokens[ENV['VAULT_ADDR']] = STDIN.read when 'erase' // Delete the token entry if it exists tokens.delete!(ENV['VAULT_ADDR']) end // Update the token file File.open("#{ENV['HOME']}/.vault_tokens", 'w') { |file| file.write(tokens.to_json) } ```