← Lessons/Anatomy of a JWT
← Anatomy of a JWT

Decode the payload properly

Learn

Why base64 -d breaks on the payload

Try base64 -d on segment 2 and it fails with invalid input, for two reasons:

  • the segment contains _ (or -), which plain base64 doesn't allow;
  • its length isn't a multiple of 4, because the = padding was stripped.

Undo both and it decodes. Writing this once as a function makes it reusable for all three segments:

b64url_decode() {
  local s
  s=$(tr '_-' '/+')                          # base64url -> base64 alphabet
  while (( ${#s} % 4 )); do s+="="; done     # restore padding
  printf '%s' "$s" | base64 -d
}

A function in a pipeline reads from stdin, so tr with no file argument consumes whatever is piped in: echo "$token" | cut -d. -f2 | b64url_decode.

Plain base64 -d fails on this payload. Write a b64url_decode function that reads stdin, maps base64url back to base64 (_→/, -→+), adds = padding until the length is a multiple of 4, and decodes. Use it to decode the payload (segment 2) into a payload variable, and pretty-print it with jq.

$ bash solution.sh
Loading...

Output

Run your solution to see its output here.