Invalid signature with HS256 token

Hello, I am generating a JWT token with version 10.2 of keycloak (dockers). I am using the HS256 algorithm but when the token is generated the signature is not valid if I check it in jwt.io. If I generate the token with RS256 the signature is valid.
If I sign with the secret from jwt.io the token authentication works correctly (I am integrating it with prosody) but if I directly use the token generated by keycloak, prosody returns invalid signature.

Is there something to be done for keycloak to properly sign an HS256 token?
Thank you

Hello, Have you got any solution to this issue

To get the secret used for signing/verifying HS256 tokens, try using the following SQL:

SELECT value FROM component_config CC INNER JOIN component C ON(CC.component_id = C.id) WHERE C.realm_id = '<realm-id-here>' and provider_id = 'hmac-generated' AND CC.name = 'secret';

If you use the resulting secret to verify the tokens, the signature should match. I’m not sure if this secret is available through the UI, probably not.

1 Like

Have you solved this issue? I’m facing the same. The generated secret for anything signed with HS256 does not work with at least 3 .NET libraries I’ve tried and at least 3 online tools.

The secret obtained by the above SQL is already encoded using base64url. Decoding is needed to get the original secret key which can then be used into libraries.

@very_vegetable I don’t think that’s accurate. Here is the secret which as you can tell is not bas64url encoded:
_RFrSRHwgjCQ0nzbAp6eDXdxCvdZOMEZBjHQO_-Qqkw_avwh_dL6aoph4kYOc1QWteDq9Qs4gBet-eLrVnnM1Q

Trying to decoded that using base64url, you run into padding issues. I’m at a loss as to how to properly get the underlying secret that would be used to populate configuration statically (legacy apps)

This looks like a base64url encoded string. Try to use the following as the secret and see whether the signature can be verified. b'\xfd\x11kI\x11\xf0\x820\x90\xd2|\xdb\x02\x9e\x9e\rwq\n\xf7Y8\xc1\x19\x061\xd0;\xff\x90\xaaL?j\xfc!\xfd\xd2\xfaj\x8aa\xe2F\x0esT\x16\xb5\xe0\xea\xf5\x0b8\x80\x17\xad\xf9\xe2\xebVy\xcc\xd5'

@very_vegetable appreciate the effort. It did not work. I actually tried this value you provided using a python script I wrote earlier:

`
import base64

key = “RFrSRHwgjCQ0nzbAp6eDXdxCvdZOMEZBjHQO-Qqkw_avwh_dL6aoph4kYOc1QWteDq9Qs4gBet-eLrVnnM1Q”

decoded = base64.urlsafe_b64decode(key + ‘=’ * (4 - len(key) % 4))

print(decoded)

`

Any other ideas? Note: If a key was signed with RSA…using the value straight from the DB works without issue.

Right, using the public key provided by Keycloak to verify a RSA signed token works without any issues. Initially I also ran into the problem to verify an HS256 signed token using the secret key got from Keycloak DB. Then decoding that key works for me. I used the following script to get the decoded secret key.

  def base64url_decode(input):
    if isinstance(input, str):
      input = input.encode("ascii")
    rem = len(input) % 4
    if rem > 0:
        input += b"=" * (4 - rem)
    return base64.urlsafe_b64decode(input)

And then using pyjwt library to decode the token works for me.

decoded_secret_key = base64url_decode('secret key got from DB')
jwt.decode(id_token, decoded_secret_key, algorithms="HS256", option={'verify_signature': True})

Also online tools like https://jwt.io/ also works. Just use the secret key got from DB and check secret base64 encoded box.

The key in your code is slightly different from the one you provided earlier. Probably just a typo.

@very_vegetable You were correct! It was a typo and it is stored in the DB as base64url encoded. I was able to verify it using pyjwt (with the addition of needing to designate the aud for signature verification). Thank you for the pointers!