Closed katsar0v closed 5 years ago
I just tried on JWT.io and I got valid for the first, and invalid for the second.
I can see it turns to the second one?
Ok, I can reproduce that. Running some tests. Just to be clear, is your expectation this this should match JWT.io's JavaScript results?
Here's the issue. The key field on JWT.io expects a series of binary bytes (00FFAA being actually 0x00 0xFF 0xAA) and not a literal string. LibJWT and the PHP you used would expect something more like:
unsigned char key[] = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF";
As opposed to
unsigned char key[] = "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF";
These two things are quite different. If I use the first in LibJWT then I get VALID for the first token, but I have to use the second to get VALID for the second token.
So this is a non-issue in LibJWT, it's just confusion between string and binary in representing of the key.
The issue is that libjwt does not accept the second token as valid, though it is valid in jwt.io
My expectation is libjwt to accept second token, which is accepted by jwt.io
It does. These two tests pass:
START_TEST(test_jwt_decode_hs256_issue_1)
{
const char token[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzb21lLWxvbmctdXVpZCIsImZpcnN0TmFtZSI6ImhlbGxvIiwibGFzdE5hbWUiOiJ3b3JsZCIsInJvbGVzIjpbInRoaXMiLCJ0aGF0IiwidGhlb3RoZXIiXSwiaXNzIjoiaXNzdWVyIiwicGVyc29uSWQiOiI3NWJiM2NjNy1iOTMzLTQ0ZjAtOTNjNi0xNDdiMDgyZmFkYjUiLCJleHAiOjE5MDg4MzUyMDAsImlhdCI6MTQ4ODgxOTYwMCwidXNlcm5hbWUiOiJoZWxsby53b3JsZCJ9.tJoAl_pvq95hK7GKqsp5TU462pLTbmSYZc1fAHzcqWM";
char key256[] = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF";
jwt_t *jwt;
int ret;
ret = jwt_decode(&jwt, token, key256, sizeof(key256));
ck_assert_int_eq(ret, 0);
ck_assert(jwt != NULL);
jwt_free(jwt);
}
END_TEST
START_TEST(test_jwt_decode_hs256_issue_2)
{
const char token[] = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzb21lLWxvbmctdXVpZCIsImZpcnN0TmFtZSI6ImhlbGxvIiwibGFzdE5hbWUiOiJ3b3JsZCIsInJvbGVzIjpbInRoaXMiLCJ0aGF0IiwidGhlb3RoZXIiXSwiaXNzIjoiaXNzdWVyIiwicGVyc29uSWQiOiI3NWJiM2NjNy1iOTMzLTQ0ZjAtOTNjNi0xNDdiMDgyZmFkYjUiLCJleHAiOjE5MDg4MzUyMDAsImlhdCI6MTQ4ODgxOTYwMCwidXNlcm5hbWUiOiJoZWxsby53b3JsZCJ9.GpCRdGxE4uClX6Vg7eAPwG-37ZvNBQXyfcldKzDG_QI";
char key256[] = "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF";
jwt_t *jwt;
int ret;
ret = jwt_decode(&jwt, token, key256, strlen(key256));
ck_assert_int_eq(ret, 0);
ck_assert(jwt != NULL);
jwt_free(jwt);
}
END_TEST
The issue isn't that it doesn't work, it's that you used the key as a string where as JWT.io assumes the "string" is actually a string of bytes in hex format.
I'm going to assume that nginx is using that key as a "string of bytes in hex format" like JWT.io is, and when you generated the token using PHP, you used it as a string of chars.
You need to make sure that PHP uses a string of bytes in hex, like I have in the above example, where each pair has \x
prepended to it.
Thank you for the clarification, will see how to implement this in PHP. I also tried with Python, same result. Maybe some clarification / documentation would be useful, I know this library is only for C intended, but JWT is usually language independent. I didn't know that the key should be a string of bytes in hex.
I guess with python this is accomplished this way:
bytes.fromhex('00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF')
In python actually there is the PyJWT lib, which does not say anything about bytes in hex.
This is what I get with PyJWT:
Token is eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzb21lLWxvbmctdXVpZCIsImZpcnN0TmFtZSI6ImhlbGxvIiwibGFzdE5hbWUiOiJ3b3JsZCIsInJvbGVzIjpbInRoaXMiLCJ0aGF0IiwidGhlb3RoZXIiXSwiaXNzIjoiaXNzdWVyIiwicGVyc29uSWQiOiI3NWJiM2NjNy1iOTMzLTQ0ZjAtOTNjNi0xNDdiMDgyZmFkYjUiLCJleHAiOjE5MDg4MzUyMDAsImlhdCI6MTQ4ODgxOTYwMCwidXNlcm5hbWUiOiJoZWxsby53b3JsZCJ9.qVjiumbfcTxYglYfqH40JAjrtJOYU68znIj_CE51W0M
Each library will have language specific nuances, not to mention that something like JWT.io's UI is implemented without regard to the JavaScript language, so it definitely needs some documentation on what is expected.
LibJWT is written in C, so the key is based on C language constructs. A string of chars, bytes, hex/ascii, etc, are all defined by the C language.
I wish I could account for documenting other implementations and their possible ambiguity with regard to the format of the key. However, it's out of my control.
Still cannot generate the token you have given me in python:
>>> str(bytes.fromhex(key_str))
'b\'\\x00\\x11"3DUfw\\x88\\x99\\xaa\\xbb\\xcc\\xdd\\xee\\xff\\x00\\x11"3DUfw\\x88\\x99\\xaa\\xbb\\xcc\\xdd\\xee\\xff\''
>>> key = str(bytes.fromhex(key_str))
>>> import jwt
>>> payload = {
... "sub": "some-long-uuid",
... "firstName": "hello",
... "lastName": "world",
... "roles": [
... "this",
... "that",
... "theother"
... ],
... "iss": "issuer",
... "personId": "75bb3cc7-b933-44f0-93c6-147b082fadb5",
... "exp": 1908835200,
... "iat": 1488819600,
... "username": "hello.world"
... }
>>> algorithm = 'HS256'
>>> encoded = jwt.encode(payload, key, algorithm=algorithm)
>>> encoded
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzb21lLWxvbmctdXVpZCIsImZpcnN0TmFtZSI6ImhlbGxvIiwibGFzdE5hbWUiOiJ3b3JsZCIsInJvbGVzIjpbInRoaXMiLCJ0aGF0IiwidGhlb3RoZXIiXSwiaXNzIjoiaXNzdWVyIiwicGVyc29uSWQiOiI3NWJiM2NjNy1iOTMzLTQ0ZjAtOTNjNi0xNDdiMDgyZmFkYjUiLCJleHAiOjE5MDg4MzUyMDAsImlhdCI6MTQ4ODgxOTYwMCwidXNlcm5hbWUiOiJoZWxsby53b3JsZCJ9.X1iI3-wIq5a3EYfwzjuOFOYIUVDA1tIJALCiCxWonjc'
Seems this issue only happens here, because in Python and PHP I am able to generate the same JWT tokens, which for some reason are not valid in libjwt for c
START_TEST(test_jwt_decode_hs256_issue_3)
{
const char token[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzb21lLWxvbmctdXVpZCIsImZpcnN0TmFtZSI6ImhlbGxvIiwibGFzdE5hbWUiOiJ3b3JsZCIsInJvbGVzIjpbInRoaXMiLCJ0aGF0IiwidGhlb3RoZXIiXSwiaXNzIjoiaXNzdWVyIiwicGVyc29uSWQiOiI3NWJiM2NjNy1iOTMzLTQ0ZjAtOTNjNi0xNDdiMDgyZmFkYjUiLCJleHAiOjE5MDg4MzUyMDAsImlhdCI6MTQ4ODgxOTYwMCwidXNlcm5hbWUiOiJoZWxsby53b3JsZCJ9.qVjiumbfcTxYglYfqH40JAjrtJOYU68znIj_CE51W0M";
const char key256[] = "00112233445566778899AABBCCDDEEFF001122334455"
"66778899AABBCCDDEEFF";
jwt_t *jwt;
int ret;
ret = jwt_decode(&jwt, token, (const unsigned char *)key256, strlen(key256));
ck_assert_int_eq(ret, 0);
ck_assert(jwt != NULL);
jwt_free(jwt);
}
END_TEST
This test succeeds for me and verifies. I'm unsure how you are trying to validate in LibJWT, but since I can do it in LibJWT directly, I can only assume it's nginx that is getting in the way of proper validation. Maybe you should bring this up with them.
Better yet, use the hex bytes in Python or PHP like I suggested:
key = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"
This is the relevant code in ngx-http-auth-jwt
// convert key from hex to binary, if a symmetric key
auth_jwt_algorithm = jwtcf->auth_jwt_algorithm;
if (auth_jwt_algorithm.len == 0 || (auth_jwt_algorithm.len == sizeof("HS256") - 1 && ngx_strncmp(auth_jwt_algorithm.data, "HS256", sizeof("HS256") - 1)==0))
{
keylen = jwtcf->auth_jwt_key.len / 2;
keyBinary = ngx_palloc(r->pool, keylen);
if (0 != hex_to_binary((char *)jwtcf->auth_jwt_key.data, keyBinary, jwtcf->auth_jwt_key.len))
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to turn hex key into binary");
goto redirect;
}
}
As you can see, the string is assumed to be a hex representation of a binary key. The README.md does not document this properly. So in order for you to get a proper validation, use the string of \x encoded bytes to generate the token.
It does not seem to work again:
katsarov@katsarov-ThinkPad-T470s:~$ python
Python 3.6.5 |Anaconda, Inc.| (default, Apr 29 2018, 16:14:56)
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import jwt
>>> payload = {
... "sub": "some-long-uuid",
... "firstName": "hello",
... "lastName": "world",
... "roles": [
... "this",
... "that",
... "theother"
... ],
... "iss": "issuer",
... "personId": "75bb3cc7-b933-44f0-93c6-147b082fadb5",
... "exp": 1908835200,
... "iat": 1488819600,
... "username": "hello.world"
... }
>>> key = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"
>>> encoded = jwt.encode(payload, key, algorithm='HS256')
>>> encoded
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzb21lLWxvbmctdXVpZCIsImZpcnN0TmFtZSI6ImhlbGxvIiwibGFzdE5hbWUiOiJ3b3JsZCIsInJvbGVzIjpbInRoaXMiLCJ0aGF0IiwidGhlb3RoZXIiXSwiaXNzIjoiaXNzdWVyIiwicGVyc29uSWQiOiI3NWJiM2NjNy1iOTMzLTQ0ZjAtOTNjNi0xNDdiMDgyZmFkYjUiLCJleHAiOjE5MDg4MzUyMDAsImlhdCI6MTQ4ODgxOTYwMCwidXNlcm5hbWUiOiJoZWxsby53b3JsZCJ9.cFUZTwXPKzBwQ26rYlKDEzZgNZychTDnCZnhRszXNyw'
Then I get following logs:
2019/01/07 08:31:23 [error] 16#16: *1 Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzb21lLWxvbmctdXVpZCIsImZpcnN0TmFtZSI6ImhlbGxvIiwibGFzdE5hbWUiOiJ3b3JsZCIsInJvbGVzIjpbInRoaXMiLCJ0aGF0IiwidGhlb3RoZXIiXSwiaXNzIjoiaXNzdWVyIiwicGVyc29uSWQiOiI3NWJiM2NjNy1iOTMzLTQ0ZjAtOTNjNi0xNDdiMDgyZmFkYjUiLCJleHAiOjE5MDg4MzUyMDAsImlhdCI6MTQ4ODgxOTYwMCwidXNlcm5hbWUiOiJoZWxsby53b3JsZCJ9.cFUZTwXPKzBwQ26rYlKDEzZgNZychTDnCZnhRszXNyw, client: 172.18.0.1, server: localhost.com, request: "GET /secret-page/ HTTP/2.0", host: "localhost.com"
2019/01/07 08:31:23 [error] 16#16: *1 failed to parse jwt, client: 172.18.0.1, server: localhost.com, request: "GET /secret-page/ HTTP/2.0", host: "localhost.com"
I can't generate the token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzb21lLWxvbmctdXVpZCIsImZpcnN0TmFtZSI6ImhlbGxvIiwibGFzdE5hbWUiOiJ3b3JsZCIsInJvbGVzIjpbInRoaXMiLCJ0aGF0IiwidGhlb3RoZXIiXSwiaXNzIjoiaXNzdWVyIiwicGVyc29uSWQiOiI3NWJiM2NjNy1iOTMzLTQ0ZjAtOTNjNi0xNDdiMDgyZmFkYjUiLCJleHAiOjE5MDg4MzUyMDAsImlhdCI6MTQ4ODgxOTYwMCwidXNlcm5hbWUiOiJoZWxsby53b3JsZCJ9.tJoAl_pvq95hK7GKqsp5TU462pLTbmSYZc1fAHzcqWM
Are you able to generate it using the same key? The library works with this key, but with none of mine
Okay I succeeded using this key:
katsarov@katsarov-ThinkPad-T470s:~$ php -a
Interactive mode enabled
php > $headers = array('alg' => 'HS256', 'typ' => 'JWT');
php > $payload = array (
php ( 'sub' => 'some-long-uuid',
php ( 'firstName' => 'hello',
php ( 'lastName' => 'world',
php ( 'roles' =>
php ( array (
php ( 0 => 'this',
php ( 1 => 'that',
php ( 2 => 'theother',
php ( ),
php ( 'iss' => 'issuer',
php ( 'personId' => '75bb3cc7-b933-44f0-93c6-147b082fadb5',
php ( 'exp' => 1908835200,
php ( 'iat' => 1488819600,
php ( 'username' => 'hello.world',
php ( );
php > $key = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF";
php > $headers_encoded = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode(json_encode($headers)));
php > $payload_encoded = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode(json_encode($payload)));
php > $signature = hash_hmac('sha256', $headers_encoded . "." . $payload_encoded, $key, true);
php > $signature_encoded = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
php > $jwt = $headers_encoded . "." . $payload_encoded . "." . $signature_encoded;
php > echo $jwt;
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzb21lLWxvbmctdXVpZCIsImZpcnN0TmFtZSI6ImhlbGxvIiwibGFzdE5hbWUiOiJ3b3JsZCIsInJvbGVzIjpbInRoaXMiLCJ0aGF0IiwidGhlb3RoZXIiXSwiaXNzIjoiaXNzdWVyIiwicGVyc29uSWQiOiI3NWJiM2NjNy1iOTMzLTQ0ZjAtOTNjNi0xNDdiMDgyZmFkYjUiLCJleHAiOjE5MDg4MzUyMDAsImlhdCI6MTQ4ODgxOTYwMCwidXNlcm5hbWUiOiJoZWxsby53b3JsZCJ9.tJoAl_pvq95hK7GKqsp5TU462pLTbmSYZc1fAHzcqWM
@benmcollins how do you generate
"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"
In python or PHP?
I did it in python:
# 3A98 is hex formatted key
signature = hmac.new(binascii.unhexlify('3A98'), signing_input, hashlib.sha256).digest().replace('=','')
signature_encoded = base64.urlsafe_b64encode(signature).replace(b'=',b'')
Good deal. I would definitely pass along to the ngx-http-auth-jwt team that they need to document that auth_jwt_key is expected to be binhex format. This has caused a lot of confusion and lost time on your part, and I can only imagine it would be the same for others.
Yes, this is solved. Since JWT is something used in many platforms and languages, this problem might occure more often than we think, thank you again for your help.
I updated the read-me on the nginx module to clarify.
https://github.com/TeslaGov/ngx-http-auth-jwt-module/blob/master/README.md
On Mon, Jan 7, 2019 at 9:04 AM Kristiyan notifications@github.com wrote:
Yes, this is solved. Since JWT is something used in many platforms and languages, this problem might occure more often than we think, thank you again for your help.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/benmcollins/libjwt/issues/79#issuecomment-451944534, or mute the thread https://github.com/notifications/unsubscribe-auth/AF68miIGelQWNArphocCsnwaUcFZQzFFks5vA1QAgaJpZM4ZqAZX .
@fitzyjoe Thanks!
Guys, I've read this thread multiple times, but I am still struggling with getting aligned with jwt.io. I am generating JWT using Simple JWT Login for Wordpress (https://wordpress.org/plugins/simple-jwt-login/#description). It returns excatly the same key like jwt.io.
My secret is: 24D996622132DA66448F1ECDE4B2B5B4D906AD4A43D1CA0D983E8BD87F3F9F98
Header: { "typ": "JWT", "alg": "HS256" }
payload: { "iat": 1669650310, "exp": 1669653910, "email": "jwt_test@gmail.com", "username": "jwt_test" }
so my token is: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2Njk2NTAzMTAsImV4cCI6MTY2OTY1MzkxMCwiZW1haWwiOiJqd3RfdGVzdEBnbWFpbC5jb20iLCJ1c2VybmFtZSI6Imp3dF90ZXN0In0.kWAnL-JZFE1MYKXZHppPZ4mv7ov5zw-iBwUlAGy3bNk
Thanks to @conor-ettinoffe I took my secret into hex bytes and was able to generate token in python locally:
import binascii
import hashlib
import hmac
import json
import secrets
secrets.token_hex(32).upper()
header ='{"typ": "JWT", "alg": "HS256"}'.encode().replace(b' ', b'')
payload = ' "iat": 1669650310, "exp": 1669653910,"email": "jwt_test@gmail.com", "username": "jwt_test"'.encode().replace(b' ', b'')
signing_input = base64.urlsafe_b64encode(header).replace(
b'=', b'')+b'.'+base64.urlsafe_b64encode(payload).replace(b'=', b'')
signature = hmac.new(binascii.unhexlify('24D996622132DA66448F1ECDE4B2B5B4D906AD4A43D1CA0D983E8BD87F3F9F98'),
signing_input, hashlib.sha256).digest().replace(b'=', b'')
signature_encoded = base64.urlsafe_b64encode(signature).replace(b'=', b'')
print((signing_input+b'.'+signature_encoded).decode())
I get: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.ImlhdCI6MTY2OTY1MDMxMCwiZXhwIjoxNjY5NjUzOTEwLCJlbWFpbCI6Imp3dF90ZXN0QGdtYWlsLmNvbSIsInVzZXJuYW1lIjoiand0X3Rlc3Qi.LC2VeEqCMy0A_wdYQtlJ72KEJgIXKQoDL2aaU1RnBYY
This token works for nginx, but it's diffrent than the previous one. I have tried to pass it in '\x24\xD9\x96\x62\x21\x32\xDA\x66\x44\x8F\x1E\xCD\xE4\xB2\xB5\xB4\xD9\x06\xAD\x4A\x43\xD1\xCA\x0D\x98\x3E\x8B\xD8\x7F\x3F\x9F\x98' format, to jwt.io, but no success.
What to do make them aligned? Either make nginx to accept the first one or generate the second one in jwt.io? @katsar0v @benmcollins @fitzyjoe You seem to understand the stuff much better :)
Sorry if the answer is above, but I still can't find it.
The first one shows "Invalid signature" on JWT.io. It's not a valid JWT.
I'm unsure how that second one would work on nginx. I see this with it on JWT.io
What you've shown is two JWT tokens that are not valid, so they cannot work.
If I take your original header, payload, and key and put it in JWT.io (base64 encode of the key). I get this token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2Njk2NTAzMTAsImV4cCI6MTY2OTY1MzkxMCwiZW1haWwiOiJqd3RfdGVzdEBnbWFpbC5jb20iLCJ1c2VybmFtZSI6Imp3dF90ZXN0In0.Ot83IRpjWixa-bJPhYP2pSCzYtTZtY6imTDdTs2tGHA
I can then plug this into a simple routine and LibJWT validates it no problem:
const char token[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2Njk2NTAzMTAsImV4cCI6MTY2OTY1MzkxMCwiZW1haWwiOiJqd3RfdGVzdEBnbWFpbC5jb20iLCJ1c2VybmFtZSI6Imp3dF90ZXN0In0.Ot83IRpjWixa-bJPhYP2pSCzYtTZtY6imTDdTs2tGHA";
// Key in bytes, base64 is: "JNmWYiEy2mZEjx7N5LK1tNkGrUpD0coNmD6L2H8/n5g"
unsigned char key256[] = { 0x24, 0xD9, 0x96, 0x62, 0x21, 0x32, 0xDA, 0x66,
0x44, 0x8F, 0x1E, 0xCD, 0xE4, 0xB2, 0xB5, 0xB4,
0xD9, 0x06, 0xAD, 0x4A, 0x43, 0xD1, 0xCA, 0x0D,
0x98, 0x3E, 0x8B, 0xD8, 0x7F, 0x3F, 0x9F, 0x98 };
jwt_t *jwt;
int ret;
ret = jwt_decode(&jwt, token, key256, sizeof(key256));
// ret == 0 here for success
@benmcollins thank you for so quick reply!
It's a little surprising, but when I put header, payload and secret I get this:
Have you got any idea where this discrepancy come from?
@TomaszWojtas
This is using your key as a string and not hex. It is also not in base64. See my code above for the base64.
I have two tokens:
First one is a test token from https://github.com/TeslaGov/ngx-http-auth-jwt-module/blob/master/test.sh, second one I generated using PHP. According to jwt.io, the first token is not valid, the second is valid. But when I use the nginx module which uses
jwt_decode
from libjwt (which I compiled and installed), the first token is valid, second is invalid. Algorithm isHS256
.Secret for testing is
00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF