Base64URL Codec

RFC 7515/RFC 4648 base64url encoding and decoding without padding:

Implementation

Javascript implementation:


/**
 * https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
 */
const base64Encode = str =>
  btoa(
    encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) =>
      String.fromCharCode("0x" + p1)
    )
  );

const base64Decode = str =>
  decodeURIComponent(
    atob(str)
      .split("")
      .map(c => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
      .join("")
  );

/**
 * https://tools.ietf.org/html/rfc7515#appendix-C
 */
const base64UrlEncode = str =>
  base64Encode(str)
    .split("=")[0]
    .replace(/\+/g, "-")
    .replace(/\//g, "_");

const base64UrlDecode = str =>
  base64Decode(
    str
      .replace(/-/g, "+")
      .replace(/_/g, "/")
      .padEnd(str.length + (4 - str.length % 4) % 4, "=")
  );

download: base64url.js

Bash implementation:

#!/bin/bash

usage() {
  cat <<EOF
RFC 7515/RFC 4648 base64url encoding and decoding without padding.

usage:
       echo abdc | base64url -E
       base64url -E abdc
       base64url.sh -D YWJjZA
       echo YWJjZA | base64url.sh -D

EOF
}

encode() {
  tr -d '[:space:]' | openssl base64 -e -A | tr -- '+/' '-_' | tr -d =
}

decode() {
  local str
  local pad
  str=$(tr -d '[:space:]' | tr -- '-_' '+/')
  pad=$(( (4 - ${#str} % 4) %4 ))
  printf "%s%s" "$str" "$(printf '=%.0s' $(seq $pad))" | openssl base64 -d -A
}

if [[ $1 == -E ]]
then
  if [[ -z $2 ]]
  then
    encode
  else
    printf "%s" "$2" | encode | xargs printf "%s\\n"
  fi

elif [[ $1 == -D ]]
then
  if [[ -z $2 ]]
  then
    decode
  else
    printf "%s" "$2" | decode | xargs printf "%s\\n"
  fi

else
  usage
fi

download: base64url.sh

JSON Web Token Example

We can make a command-line version of jwt.io by using jq to decode and format a JSON Web Token (JWT):

#!/bin/bash

jq -sR 'split(".")[0,1] | gsub("-";"+") | gsub("_";"/") | @base64d | fromjson
    | if has("exp")       then .exp       |= todate else . end
    | if has("iat")       then .iat       |= todate else . end
    | if has("nbf")       then .nbf       |= todate else . end
    | if has("auth_time") then .auth_time |= todate else . end' "$@"

download: jwt.sh

On macOS with a JWT copied to the clipboard, this little helper is very convenient:

#!/bin/bash

pbpaste | jwt.sh
echo

download: pbpaste_jwt