0

I have a Java Spring boot API that a user logs in and is issued a JWT token ( i cant change this code). I have a new python API that needs to parse the JWT to verify its been authenticated.

Java Code

import io.jsonwebtoken.Jwts;

   private String secretKey = "CFB86D5E4DC4C11C6AFA9E5DF5AD9"

   String jwt = Jwts.builder()
          .setSubject(userByUsername.getUsername())
          .setIssuedAt(now)
          .setNotBefore(now)
          .setIssuer("my-authenticator")
          .setExpiration(new Date(System.currentTimeMillis() + (1000L * tokenMaxAge)))
          .signWith(SignatureAlgorithm.HS256, secretKey)
          .compact();

Inside my python code i have

import jwt

    token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY3NDUwMzE2NSwibmJmIjoxNjc0NTAzMTY1LCJpc3MiOiJ0ZXN0IiwiZXhwIjoxNjc0NTA2NzY1fQ.wPc98PTVmZKKUEBmuKZG3Z_fXrC7QLLpLE9BXHR3Sw4"
    key = 'CFB86D5E4DC4C11C6AFA9E5DF5AD9'

    jwt_options = {
        'verify_signature': True,
        'verify_exp': False,
        'verify_nbf': False,
        'verify_iat': True,
        'verify_aud': False
    }

    parts = jwt.decode(token, key, algorithms="HS256", options=jwt_options)

    print(parts)

If I set verify_signature = False everything works and i can parse the jwt. But I need to have this set to true. If I go to jwt.io the signature shows up as verified enter image description here I've tried playing around with encoding/decoding the string but Im not sure what I'm missing

I have tried decoding and encoding the key but havn't had success. The secret is the same in the java application and python application

ex1. key = b'CFB86D5E4DC4C11C6AFA9E5DF5AD9'

ex2. key = str(base64.urlsafe_b64decode(CFB86D5E4DC4C11C6AFA9E5DF5AD9), 'utf-8')

ex3. key = base64.urlsafe_b64decode(CFB86D5E4DC4C11C6AFA9E5DF5AD9)

ex4. key = base64.b64decode('CFB86D5E4DC4C11C6AFA9E5DF5AD9') # this gives binascii.Error: Invalid base64-encoded string: number of data characters (29) cannot be 1 more than a multiple of 4

Solution:

So I was able to solve my question but im not sure why it worked. The first consisted of setting my secret to a 256 character string ex. 73357638792F423F4428472B4B6250655368566D597133743677397A24432646 The next step was to encode it to UTF-8 and then b64encode it so:

 jwt_options = {
     'verify_signature': True,
     'verify_exp': False,
     'verify_nbf': False,
     'verify_iat': True,
     'verify_aud': False
 }

 signature_key = config.config.signature_key
 signature_key = b64decode(signature_key.encode("utf-8"))

 parts = jwt.decode(self.token, signature_key, algorithms=["HS256"], options=jwt_options)

Parker Dell
  • 472
  • 4
  • 11
  • Did you check if the token is already expired? – Unmitigated Jan 24 '23 at 16:18
  • Right now I dont care if password is expired, i just changed the comment to ignore exp check for now since i know that part works – Parker Dell Jan 24 '23 at 16:21
  • 1
    The token that you show in your Python example **can't** be verified with the secret that you showed us. And on jwt.io you made a common mistake in using the tool and got a false verification: You clicked on "secret base64 encoded" (which is not the case) and that changed the signature. In [my answer here](https://stackoverflow.com/questions/69862105/jwt-io-says-signature-verified-even-when-key-is-not-provided) I describe how to do it right. – jps Jan 24 '23 at 16:29
  • Aside from that, the Python code looks fine, and wonder if you just made a mistake by copying back the token from jwt.io to your code instead of using the original token from your Java code. – jps Jan 24 '23 at 16:30
  • I followed the steps you listed, i added the key first (checked the box for encoded) `CFB86D5E4DC4C11C6AFA9E5DF5AD9` and then entered the jwt and it shows verified `eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY3NDUwMzE2NSwibmJmIjoxNjc0NTAzMTY1LCJpc3MiOiJ0ZXN0IiwiZXhwIjoxNjc0NTA2NzY1fQ.wPc98PTVmZKKUEBmuKZG3Z_fXrC7QLLpLE9BXHR3Sw4` – Parker Dell Jan 24 '23 at 16:34
  • no, clicking on the box "secret base64 encoded" is the wrong part. The secret is not base64 encoded. It's a hex ascii string. Java treats it as a normal string when it signs the token. I believe the token that your Java code created is not the one you show in your python example. Please check again. (The token in your Python example looks identical to the one on the jwt.io screenshot) – jps Jan 24 '23 at 16:38
  • I was able to verify that the code matches. For testing purposes i changed the secret and generated a new token with it `687ADCC21ACAC129ED4BA3781759F` and token `eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJyb290IiwiaWF0IjoxNjc0NTg0NjY4LCJuYmYiOjE2NzQ1ODQ2NjgsImlzcyI6ImRlZXBjb3JlIiwiZXhwIjoxNjc0NTg4MjY4fQ.9RYbzL1s7ZkNTr0KzTj7RSuocdNxJdc8KI9PXuYyzTA` – Parker Dell Jan 24 '23 at 18:27
  • What does it mean now? Can you verify a token from Java in your Python code? – jps Jan 24 '23 at 18:47
  • sorry for lack of clarification. I meant i went into the java code and printed out the secret and then made a new token and still get errors – Parker Dell Jan 24 '23 at 18:57

0 Answers0