Should I be able to see patterns in a HS256 encoded JWT?

tl/dr: Your selected version of the JWT doesn't encrypt anything, it merely encodes it for easy transport. The data in the payload is not meant to be a secret.

You have a JWS (JWT with signature). What you are looking at is simply the base64 encoded data payload. A JWS contains 3 parts:

  1. The base64 encoded header
  2. The base64 encoded data
  3. A cryptographic signature

Base64 is simply an encoding format - not any kind of encryption, and is not meant to hide the data. Rather, it just makes sure it is composed solely of standard ASCII characters that easily survive transfer between different systems. As a result, if you were to take everything in between the two periods and run it through a base64 decoder, you would see your original payload data without issue.

The key therefore is simple: a JWS isn't meant to hide the data. It is simply intended (through the signature) to ensure data integrity, i.e. if someone changes the data payload then you will know because your signature will no longer match.

Alternately you could use a JWE (JWT with encryption) to hide your data. See Bob's excellent answer for a more detailed comparison between JWT, JWS, and JWE, all of which are closely related.

There's a bit of confusion of terminology here.

JWT defines the basic format of the claims, and some standard claims. It specifies that the JWT Claims Set should either be the payload of a JWS or a JWE structure.

JWS defines a structure for some payload with a signature. While the payload is almost always JWT in practice, this is not a requirement of the specification. The most common form is the JWS Compact Serialization, which is the Base64'd Header.Payload.Signature you are familiar with. Note there is no encryption involved, only signing. This can1 guarantee that the token was created by a trusted party and not modified (authenticity), but will not hide its contents.

JWE is the encrypted counterpart to JWS. Much like JWS, it most often contains a JWT payload (as its plaintext) but this is not a requirement. JWE Compact Serialization is somewhat different from the JWS equivalent: Header.Key.IV.Ciphertext.AuthenticationTag. This should1 have the same security guarantees (authenticity)2 as JWS, with the addition of hiding the message from anyone without the key (confidentiality).

What you have there is specifically a JWS, which is signed but not encrypted (as seen in the HS256 algorithm, which stands for "HMAC using SHA-256"). If you need encryption, you should instead create a JWE with one of the encryption algorithms defined by JWA.

Further reading:

  • Understanding ID Token
  • JWT, JWS and JWE for Not So Dummies! (Part I)
  • RFC 7519 JSON Web Token (JWT)
  • RFC 7515 JSON Web Signature (JWS)
  • RFC 7516 JSON Web Encryption (JWE)

1 As always, any "guarantees" depend on everything being configured correctly. And that you're not e.g. using a debugging config that leaves everything unencrypted/unsigned.

2 Assuming authenticated encryption.

What you're missing is that your token is signed (or, more precisely, authenticated with a symmetric key) but not encrypted.

If you take the token in your question above, split it into three pieces at the periods (.) and feed each piece into a base64 decoder, you'll get the following decoded outputs:


and a sequence of 32 mostly non-ASCII bytes which is the 256-bit HMAC authentication tag for the rest of the token. As you can see, all the data is there easily readable by anyone. The authentication tag only prevents anyone who doesn't know the secret HMAC key from modifying the token or creating forged tokens from scratch.