Json Web Tokens (JWTs) are base64 encoded strings. This is an example of JWT pulled from jwt.io
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
It consists of three parts separated by a period ("."
):
- Header -
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
- Payload -
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
- Signature -
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
To decode using Bash, we can decode those three parts as a single string or separately:
To decode the JWT from before:
$ echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" | base64 --decode --ignore-garbage
{"alg":"HS256","typ":"JWT"}{"sub":"1234567890","name":"John Doe","iat":1516239022}���pD��x�����
Lx�����"Ui�,�\%
As you can see, we have the header, payload, and signature displayed one after the other in the output.
Note that:
The last section in the JWT, the signature, is also base64-url encoded, but it’s just binary data; if you try to decode it, you will end up with non-displayable characters:
https://developer.okta.com/blog/2020/12/21/beginners-guide-to-jwt
If you omit the --ignore-garbage
argument when decoding using base64
, you might only see the decoded header:
$ echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" | base64 --decode
{"alg":"HS256","typ":"JWT"}base64: invalid input
Here's the header: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
To decode:
$ echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" | base64 --decode --ignore-garbage
{"alg":"HS256","typ":"JWT"}
Here's the payload: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
To decode:
$ echo "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ" | base64 --decode --ignore-garbage
{"sub":"1234567890","name":"John Doe","iat":1516239022}base64: invalid input
(Why does it say 'invalid input')
Here's the signature: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
To decode:
$ echo "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" | base64 --decode --ignore-garbage
I�J�IHNJ(]�O��lj�~�:N�%V�B�0�base64: invalid input