In today’s digital landscape, ensuring secure and trusted communication between systems is critical, especially in web and blockchain applications. One of the most widely used technologies to achieve this is the JSON Web Token (JWT).
This blog dives into JWTs from both a technical and mathematical standpoint, and explores how they are applied in blockchain ecosystems.
🧱 JWT Structure
A JWT consists of three parts, separated by periods (.
):
..
1. Header
Contains metadata about the token:
{
"alg": "HS256",
"typ": "JWT"
}
-
alg
: Algorithm used to sign the token (e.g., HS256, RS256). -
typ
: Indicates that it's a JWT.
2. Payload
Contains the claims, which are statements about an entity (e.g., user info or permissions):
{
"userId": "12345",
"username": "JohnDoe"
}
3. Signature
Used to verify the integrity of the token and ensure it hasn’t been tampered with.
It is generated using:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secretKey
)
💡 All three parts of the JWT are Base64Url encoded.
📐 The Math Behind JWTs
Understanding the underlying cryptographic concepts adds a new level of insight into how JWTs actually work.
🔁 Hashing
JWTs use algorithms like SHA-256, a cryptographic hash function that:
- Produces a fixed-size output (256 bits).
- Is deterministic: the same input gives the same output.
- Is one-way: it's computationally infeasible to reverse the hash and get the original input.
JWTs use hashing to create a unique fingerprint of the header and payload.
✍️ Digital Signatures
JWTs support two common signing methods:
1. HMAC (HS256)
- Hash-based Message Authentication Code.
- Uses a shared secret key (symmetric encryption).
- The same key is used to sign and verify the JWT.
2. RSA (RS256)
- Uses asymmetric encryption.
- The private key signs the JWT.
- The public key verifies it.
- Common in blockchain contexts where public/private key systems are the norm.
🔤 Base64Url Encoding
This is not a cryptographic function. It simply encodes binary data into a string that is:
- URL-safe (no
+
,/
, or=
characters). - Easily transmittable via HTTP headers or URLs.
🔗 JWTs in Blockchain
JWTs play a crucial role in securing blockchain applications:
1. Authentication & Authorization
- A blockchain-based app can generate a JWT after a user logs in.
- The JWT includes claims like user ID and permissions.
- The JWT is included in subsequent API calls via the
Authorization
header. - The server verifies the JWT and grants access based on the claims.
2. API Security
- Blockchain platforms often expose APIs for smart contract interactions or querying data.
- JWTs help restrict access, ensuring only authenticated clients can interact with the blockchain.
3. Decentralized Apps (dApps)
- JWTs help manage user sessions and permissions in dApps.
- This enhances the security and UX of decentralized platforms.
4. Node Access Security
- Services like QuickNode require JWTs to control access to blockchain nodes.
- Ensures only authorized users can interact with network infrastructure.
🧪 How HS256 Works (with Example)
Let’s walk through a simplified example of how HS256 is used to generate and verify a JWT.
🛠 Step 1: JWT Creation
Header
{
"alg": "HS256",
"typ": "JWT"
}
Base64Url encoded:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload
{
"userId": "12345",
"username": "JohnDoe"
}
Base64Url encoded:
eyJ1c2VySWQiOiIxMjM0NSIsInVzZXJuYW1lIjoiSm9obkRvZSJ9
Secret Key
secretKey123
🔐 Step 2: Signature Generation
Concatenate header and payload:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NSIsInVzZXJuYW1lIjoiSm9obkRvZSJ9
Apply HMAC-SHA256 with the secret key:
HMACSHA256(secretKey123, data)
Let’s say the result is:
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
✅ Final JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VySWQiOiIxMjM0NSIsInVzZXJuYW1lIjoiSm9obkRvZSJ9.
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
🔍 Step 3: JWT Verification
When the server receives a JWT:
- It extracts the header and payload.
- It uses the same secret key to re-calculate the signature.
- If the new signature matches the one in the token:
- The token is valid.
- The data hasn’t been tampered with.
- The request is authenticated.
Base64url Encoding in JWTs: Mathematical and Bitwise Perspective
To fully understand how JWTs function under the hood, especially regarding Base64url encoding, it's helpful to break down the encoding process at the binary and mathematical levels.
What Is Base64url?
Base64url is a URL-safe variant of Base64 encoding. While Base64 is used to convert binary data into a readable ASCII string format, its output includes characters like +
, /
, and padding (=
), which can cause issues in URLs or HTTP headers. Base64url modifies this by:
- Replacing
+
with-
- Replacing
/
with_
- Omitting padding characters (
=
)
This makes the encoded string safe for use in URL parameters, filenames, and headers—perfect for JWTs.
Step-by-Step: Base64url Encoding in JWTs
Let’s walk through how the header of a JWT is encoded using Base64url, including the bit-level details and mathematical operations involved.
1. JSON to UTF-8 Encoding
Start with a typical JWT header:
{ "alg": "HS256", "typ": "JWT" }
This JSON object is serialized into a UTF-8 byte array:
7b 22 61 6c 67 22 3a 20 22 48 53 32 35 36 22 2c 20 22 74 79 70 22 3a 20 22 4a 57 54 22 7d
Each of these hexadecimal values represents a byte (8 bits).
2. Bitwise Operations
Each byte is converted into binary. For example:
-
7b
→01111011
-
22
→00100010
-
61
→01100001
- and so on...
These 8-bit chunks are concatenated into a long binary stream.
3. Chunking into 6-Bit Segments
The binary stream is then split into 6-bit segments:
011110 110010 001001 100001 ...
Each 6-bit chunk represents a number between 0 and 63.
4. Binary to Decimal Conversion
Each 6-bit chunk is converted into its decimal equivalent:
-
011110
→ 30 -
110010
→ 50 -
001001
→ 9 -
100001
→ 33
5. Mapping to Base64url Alphabet
Using the Base64url alphabet:
-
0–25
→A–Z
-
26–51
→a–z
-
52–61
→0–9
-
62
→-
-
63
→_
The values are mapped:
-
30
→e
-
50
→y
-
9
→J
-
33
→h
These characters are concatenated to form the encoded output:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
This string is the Base64url-encoded form of the JWT header.
Recap of Key Mathematical Concepts
- Bit Manipulation: Input is broken into 6-bit chunks from an 8-bit byte stream.
- Binary-to-Decimal Conversion: Each 6-bit group is interpreted using base-2 positional notation.
- Index Lookup: Decimal values are used as indices to fetch characters from the Base64url alphabet.
- URL-Safe Encoding: Replaces unsafe characters and drops padding.
Python Code Example (Revisited)
import base64
import json
def base64url_encode(data):
"""Encodes data using Base64url encoding."""
encoded_data = base64.urlsafe_b64encode(data).rstrip(b'=').decode('utf-8')
return encoded_data
header = { "alg": "HS256", "typ": "JWT" }
header_json = json.dumps(header).encode('utf-8')
encoded_header = base64url_encode(header_json)
print(encoded_header) # Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Understanding HMAC-SHA256 requires breaking it down into its two core components: SHA-256 and HMAC.
-
SHA-256 (Secure Hash Algorithm 256-bit):
- Hashing Function:
- SHA-256 is a cryptographic hash function. It takes an input (a message) and produces a fixed-size output (a 256-bit hash value).
- Key properties:
- Deterministic: The same input always produces the same output.
- One-way: It's computationally infeasible to derive the input from the output.
- Collision-resistant: It's extremely difficult to find two different inputs that produce the same output.
- Mathematical Operations:
- SHA-256 involves complex bitwise operations, including:
- Bitwise AND, OR, XOR: These operations manipulate individual bits.
- Bitwise shifts and rotations: These operations move bits within a word.
- Modular addition: Adding numbers and then taking the remainder after dividing by a fixed value.
- Nonlinear functions: These functions introduce complexity and prevent simple mathematical attacks.
- The message is processed in blocks, and these operations are repeated many times, mixing the data thoroughly.
- Padding:
- Before hashing, the input message is padded to ensure its length is a multiple of 512 bits.
-
HMAC (Hash-based Message Authentication Code):
- Message Authentication:
- HMAC uses a cryptographic hash function (like SHA-256) along with a secret key to generate a message authentication code (MAC).
- The MAC is used to verify both the integrity and the authenticity of a message.
- Mathematical Operations:
-
HMAC involves two rounds of hashing:
- Inner Hash:
- The secret key is padded or hashed to a specific length.
- This processed key is XORed with an "inner padding" constant.
- The result is concatenated with the message.
- The combined data is then hashed using SHA-256.
- Outer Hash:
- The processed key is XORed with an "outer padding" constant.
- The result is concatenated with the output of the inner hash.
- The combined data is then hashed again using SHA-256.
- Key Importance:
- The secret key is crucial for HMAC's security. Only parties with the correct key can generate and verify the MAC.
-
HMAC-SHA256 in the JWT Context:
- Application:
- In JWTs, HMAC-SHA256 is used to generate the signature.
- The input message is the concatenated Base64url-encoded header and payload.
- The secret key is a shared secret known only to the server.
- Process:
- The header and payload are concatenated.
- The server uses the secret key and the concatenated data as input to the HMAC-SHA256 algorithm.
- The algorithm performs the inner and outer hash operations described above.
- The resulting hash value is the JWT signature.
- The signature is then Base64url-encoded and appended to the JWT.
Mathematical Concepts Involved:
- Bitwise operations (AND, OR, XOR, shifts, rotations): Essential for SHA-256.
- Modular arithmetic: Used in SHA-256.
- Concatenation: Combining data.
- Hashing: Generating a fixed-size output from an arbitrary input.
- XOR operations: Used to combine the key with padding.
In essence, HMAC-SHA256 provides a robust way to ensure that a JWT has not been tampered with and that an authorized party generated it.
To delve deeper into the mathematical operations behind HMAC-SHA256 signature generation, let's break it down into the core steps and their underlying math:
-
SHA-256's Internal Math:
- Padding:
- The input message (in our case, the concatenated header and payload) is padded to a multiple of 512 bits.
- This involves appending a '1' bit, followed by '0' bits, and finally a 64-bit representation of the original message length.
- This padding is essential for the SHA-256 algorithm to work correctly.
- Message Processing:
- The padded message is divided into 512-bit chunks.
- Each chunk is processed through a series of rounds.
- Each round involves:
- Bitwise Operations:
- AND, OR, XOR operations on 32-bit words.
- Right shifts (>>) and right rotations (>>>) of bits.
- Modular Addition:
- Adding 32-bit words modulo 2^32.
- Nonlinear Functions:
- Complex functions that introduce nonlinearity, making the hash difficult to reverse. These functions use bitwise operations.
- Constants:
- Adding predefined constants to the intermediate hash values.
- These repeated operations mix the input data thoroughly, creating a seemingly random output.
- Initialization and Hash Values:
- SHA-256 uses a set of initial hash values.
- These values are updated during each round of processing.
- The final hash values are the 256-bit output.
-
HMAC's Math:
- Key Processing:
- The secret key is padded or hashed to a length of 512 bits.
- This processed key is used in both the inner and outer hash computations.
- Inner Hash:
- ipad (inner padding) is a predefined constant (0x36 repeated 64 times).
- The processed key is XORed with ipad.
- This result is concatenated with the input message (or, in the second hash, the result of the inner hash).
- This combined data is then hashed using SHA-256.
- Outer Hash:
- opad (outer padding) is another predefined constant (0x5C repeated 64 times).
- The processed key is XORed with opad.
- This result is concatenated with the output of the inner hash.
- This combined data is hashed again using SHA-256.
- Final Output:
- The output of the outer hash is the HMAC-SHA256 signature.
Mathematical Concepts:
- Bitwise Operations: Fundamental to both SHA-256 and HMAC.
- Modular Arithmetic: Used in SHA-256's addition operations.
- XOR (Exclusive OR): Used in HMAC to combine the key with padding.
- Hashing: The core function of SHA-256.
- Concatenation: Combining data.
In essence:
HMAC-SHA256 uses SHA-256's robust hashing algorithm and adds a layer of security through the secret key and the two-round hashing process. This process is heavily reliant on bitwise operations and modular arithmetic to generate a secure signature.
Let's break down HMAC-SHA256 with a simplified example. Keep in mind that real-world HMAC-SHA256 operations involve very long binary strings and are computationally intensive. This example is for illustrative purposes:
Simplified Example:
- Secret Key: key (Simplified for demonstration)
- Message: data (Simplified for demonstration)
-
SHA-256 (Simplified):
- For this example, imagine SHA-256 as a simplified hash function that just adds the ASCII values of the input, then takes the last 8 bits of that addition.
- In a real-world scenario, SHA-256 involves bitwise operations, rotations, and more complex mathematical functions.
- Real SHA-256 produces a 256-bit hash.
-
HMAC-SHA256 (Simplified):
- Key Padding:
- Let's say we pad the key to a length of 8 bytes (again, simplified).
- Padded key: key\x00\x00\x00
- Inner Hash:
- ipad (inner padding) is a constant. Let's simplify it to 0x36.
- key XOR ipad: Each byte of the padded key is XORed with 0x36.
- Concatenate: The result is concatenated with the message (data).
- Simplified SHA-256: The simplified SHA-256 is applied to this concatenated data.
- Outer Hash:
- opad (outer padding) is another constant. Let's simplify it to 0x5C.
- key XOR opad: Each byte of the padded key is XORed with 0x5C.
- Concatenate: The result is concatenated with the output of the inner hash.
- Simplified SHA-256: The simplified SHA-256 is applied to this concatenated data.
- Result:
- The output of the outer hash is the simplified HMAC-SHA256 signature.
Python Example (Simplified):
def simplified_sha256(data):
"""A very simplified hash function for demonstration."""
total = sum(ord(c) for c in data)
return total & 0xFF # Last 8 bits
def simplified_hmac_sha256(key, data):
"""A simplified HMAC-SHA256 for demonstration."""
ipad = b'\x36' * 8
opad = b'\x5c' * 8
padded_key = key.encode('utf-8') + b'\x00' * (8 - len(key))
inner_input = bytes(a ^ b for a, b in zip(padded_key, ipad)) + data.encode('utf-8')
inner_hash = simplified_sha256(inner_input.decode('utf-8'))
outer_input = bytes(a ^ b for a, b in zip(padded_key, opad)) + str(inner_hash).encode('utf-8')
outer_hash = simplified_sha256(outer_input.decode('utf-8'))
return outer_hash
key = "key"
data = "data"
signature = simplified_hmac_sha256(key, data)
print(signature)
Key Points:
- This Python code is a drastically simplified representation. Real HMAC-SHA256 implementations use cryptographic libraries and handle much more complex bitwise operations.
- The core principles of key padding, inner hashing, and outer hashing are illustrated.
- Real-world applications use libraries that handle all the complexities of the cryptographic functions.
Let's break down how HMAC-SHA256 would work with the simplified example "ok" as the key and "am" as the message, while addressing the "256 beta" concept.
Simplified Example (Conceptual):
- Secret Key: "ok"
- Message: "am"
- Simplified Hash Function: Sum the ASCII values of the input characters, then take the result modulo 256.
- ipad: 0x36 (54 in decimal)
- opad: 0x5C (92 in decimal)
Step-by-Step Breakdown (Simplified):
-
Key Padding (Conceptual):
- In a real-world scenario, the key would be padded to a block size. For simplicity, we will just use the ASCII values of the key.
- ASCII values: "o" = 111, "k" = 107
-
Inner Hash:
- Key XOR ipad:
- 111 XOR 54 = 65
- 107 XOR 54 = 57
- Concatenation:
- Combine the XORed key values (65, 57) with the ASCII values of the message "am" (97, 109).
- Sequence: 65, 57, 97, 109.
- Simplified Hash:
- 65 + 57 + 97 + 109 = 328
- 328 modulo 256 = 72
- The inner hash result is 72.
- Key XOR ipad:
-
Outer Hash:
- Key XOR opad:
- 111 XOR 92 = 199
- 107 XOR 92 = 195
- Concatenation:
- Combine the XORed key values (199, 195) with the inner hash result (72).
- Sequence: 199, 195, 72
- Simplified Hash:
- 199 + 195 + 72 = 466
- 466 modulo 256 = 210
- The outer hash result (the simplified HMAC-SHA256 signature) is 210.
- Key XOR opad:
"256 Beta" and Modulo:
- The "256" comes from the fact that we're working with bytes (8 bits), which can represent values from 0 to 255.
- The modulo operation (represented by the
%
symbol in most programming languages) finds the remainder of a division. - When we take a number modulo 256, we're essentially wrapping the result around to fit within the range of 0 to 255.
- In the example above, when we calculate 328 modulo 256, the result is 72. 328/256 = 1 with a remainder of 72.
- The Beta in this case is not a variable but refers to the fact that we are working within the range of a byte and thus the modulus of 256.
Python Representation (Simplified):
def simplified_hash(data):
"""Simplified hash function."""
total = sum(data)
return total % 256
def simplified_hmac(key, message):
"""Simplified HMAC."""
ipad = 0x36
opad = 0x5c
key1, key2 = ord(key[0]), ord(key[1])
message1, message2 = ord(message[0]), ord(message[1])
key1_xor_ipad = key1 ^ ipad
key2_xor_ipad = key2 ^ ipad
inner_hash = simplified_hash([key1_xor_ipad, key2_xor_ipad, message1, message2])
key1_xor_opad = key1 ^ opad
key2_xor_opad = key2 ^ opad
outer_hash = simplified_hash([key1_xor_opad, key2_xor_opad, inner_hash])
return outer_hash
key = "ok"
message = "am"
signature = simplified_hmac(key, message)
print(signature) # Output: 210
Important Reminders:
- This remains a highly simplified example. Real-world HMAC-SHA256 utilizes much more complex hashing and padding.
- In real-world applications, the key and messages are byte arrays, and the hash is 256 bits, not a single byte.
- The modulus 256 is used because we are working with bytes.
🔐 JWT Security: The Structure, Vulnerabilities & Quantum Threat
1. JWT Structure
- A JWT (JSON Web Token) is a data structure used for securely transmitting information between parties.
- It consists of three parts:
- Header: Specifies the algorithm used and token type.
- Payload: Contains the claims (user data, permissions, etc.).
- Signature: Ensures the data hasn’t been tampered with.
- These parts are Base64Url encoded and concatenated with dots (
.
) to form the final JWT string.
👉 Important: The JWT itself doesn’t involve heavy mathematics—it's a wrapper. The cryptographic operations that secure it are what involve complex math.
2. Cryptographic Algorithms Behind JWTs
The JWT’s security relies entirely on the cryptographic algorithm used to sign it:
Algorithm | Type | Description |
---|---|---|
HS256 | Symmetric | HMAC with SHA-256, where both parties share a secret key. |
RS256 | Asymmetric | RSA with SHA-256, using a private/public key pair. |
ES256 | Asymmetric | ECDSA with SHA-256, based on elliptic curve cryptography. |
These algorithms perform:
- Hashing (e.g., SHA-256)
- Digital signatures (RSA/ECDSA)
- Bitwise operations and modular arithmetic
- HMAC generation for integrity
So while the JWT format is lightweight, the math lives in the signature algorithms.
3. When JWTs Become Vulnerable
JWTs can be compromised not because of the token itself, but due to poor implementation or mismanagement:
Weak Practice | Risk |
---|---|
Weak or leaked secrets | Anyone can forge valid tokens. |
Insecure storage (e.g., localStorage) | Vulnerable to XSS attacks. |
HTTP instead of HTTPS | Tokens can be intercepted via MITM attacks. |
Lack of expiration checks | Old tokens may be reused indefinitely. |
Incorrect algorithm acceptance | Some libraries may be tricked into skipping validation. |
Ignoring token issuer/audience | Allows impersonation between services. |
4. Best Practices for JWT Security
To maintain strong JWT security:
- Use strong, random secrets or key pairs.
- Always verify the token’s signature.
- Use short expiration times.
- Store tokens in httpOnly, secure cookies (to protect from XSS).
- Always serve over HTTPS.
- Implement token revocation logic where needed.
- Prefer RS256 or ES256 for better separation of concerns (signing vs verification).
5. JWTs & Quantum Computing: The Looming Threat
Quantum computing introduces a theoretical risk to JWTs—not through JWTs directly, but through the cryptographic algorithms that secure them:
Quantum Threat | Targeted Crypto | Impact |
---|---|---|
Shor's Algorithm | RSA, ECDSA | Can break these algorithms entirely by factoring or solving discrete logs. |
Grover’s Algorithm | HMAC, SHA-256 | Cuts brute-force search time in half. |
⚠️ Impact on JWTs:
- If JWTs are signed using RSA or ECDSA, future quantum computers could forge tokens by breaking the digital signature.
- Even HMAC-based JWTs become weaker due to accelerated brute-force capabilities.
🔐 Current mitigation efforts:
- Research into post-quantum cryptography (PQC) is underway.
- Algorithms like SPHINCS+, CRYSTALS-Dilithium, and others aim to replace RSA/ECDSA in a quantum-safe future.
🔍 Real-World Example
Scenario: An e-commerce platform uses JWTs for user authentication.
- User logs in, and the server issues a JWT signed with RS256.
- The JWT is stored in a secure,
httpOnly
cookie and includes claims like user ID, role, and token expiry (exp
). - On every API request, the client sends the JWT.
- The server verifies the signature using the public key, checks the expiry, and grants access accordingly.
Now imagine:
- If the private key is accidentally committed to a public GitHub repo (true story for many companies!), an attacker can forge any JWT, log in as admin, and wreak havoc.
- Or if the JWT is stored in
localStorage
, an XSS attack on the frontend can steal the token and hijack the session.
✅ Conclusion
- JWTs are not inherently secure or insecure—their security depends entirely on how they’re implemented and protected.
- The math behind JWT security lies in the cryptographic algorithms, not the structure of the token itself.
- As quantum computing matures, traditional cryptographic algorithms like RSA and ECDSA may become obsolete, requiring a move to quantum-resistant algorithms.
- For now, strong key management, secure token handling, and keeping cryptographic best practices are your strongest defense.