1

I went to this website https://jwt.io/#debugger-io Here I took the given sample info and passed it to my code.

But the encoded information that I got is not matching what is given on the website. Since I am doing something wrong here, I am not able to generate the signature in a valid format.

I need to make a program for JWT verification without using PyJWT types libraries.

Here is my code

import base64
import hmac
header = {"alg": "HS256", "typ": "JWT"}
payload = {"sub": "1234567890", "name": "John Doe", "iat": 1516239022}
header = base64.urlsafe_b64encode(bytes(str(header), 'utf-8'))
payload = base64.urlsafe_b64encode(bytes(str(payload), 'utf-8'))
print(header)
print(payload)
signature = hmac.new(bytes('hi', 'utf-8'), header + b'.' + payload, digestmod='sha256').hexdigest()
print(signature)

Outputs enter image description here

jps
  • 20,041
  • 15
  • 75
  • 79
Pragyan
  • 349
  • 2
  • 14

1 Answers1

1

There are 3 things that need to be changed in your code.

  1. your header and payload are not valid JSON. If you decode the result of your Base64 encoded header eydhbGcnOiAnSFMyNTYnLCAndHlwJzogJ0pXVCd9 you get

{'alg': 'HS256', 'typ': 'JWT'}

but it should be (with "instead of ')

{"alg": "HS256", "typ": "JWT"}

  1. the function base64.b64encode produces an output that can still contain '='. The padding has to be removed.

  2. You create the signature with .hexdigest(), which produces a hex-ascii string. Instead you need to use .digest() to get binary output and then Base64URL encode the result.

The code below is a corrected version of your code which produces a JWT string that can be verified on https://jwt.io.

import base64
import hmac

header = '{"alg":"HS256","typ":"JWT"}'
payload = '{"sub":"1234567890","name":"John Doe","iat":1516239022}'

header = base64.urlsafe_b64encode(bytes(str(header), 'utf-8')).decode().replace("=", "")
payload = base64.urlsafe_b64encode(bytes(str(payload), 'utf-8')).decode().replace("=", "")
print(header)
print(payload)
signature = hmac.new(bytes('hi', 'utf-8'), bytes(header + '.' + payload, 'utf-8'), digestmod='sha256').digest()
sigb64 = base64.urlsafe_b64encode(bytes(signature)).decode().replace("=", "")
print(sigb64)
token = header + '.' + payload + '.' + sigb64
print(token)

As a sidenote: The secret that you use to create the HMAC should have a length of at least 256 bits, even if the very short key is accepted. Some libs enforce a minimum key length.

jps
  • 20,041
  • 15
  • 75
  • 79