Comments (13)
I believe this is obsoleted by:
JWT_EXPORT int jwt_decode_2(jwt_t **jwt, const char *token, jwt_key_p_t key_provider);
from libjwt.
Apologies, wrong issue.
from libjwt.
I have run into some undefined behavior that is perhaps a result of this. Using the latest master
branch:
#include <stdio.h>
#include <stdlib.h>
#include <jwt.h>
#include <string.h>
#include <time.h>
int main() {
jwt_t *jwt = NULL;
char *out = NULL;
jwt_t *decoded_jwt = NULL;
int ret;
const char *secret = "YOUR_SECRET_KEY_HERE";
// Create a new JWT object
ret = jwt_new(&jwt);
if (ret != 0) {
fprintf(stderr, "Failed to create JWT object: %s\n", strerror(ret));
return 1;
}
// Set the algorithm for the JWT
jwt_set_alg(jwt, JWT_ALG_HS256, (const unsigned char *)secret, strlen(secret));
// Add a custom grant
jwt_add_grant(jwt, "foo", "bar");
// Export the JWT as a string
out = jwt_encode_str(jwt);
if (!out) {
fprintf(stderr, "Failed to encode JWT\n");
jwt_free(jwt);
return 1;
}
// Output the generated JWT string
printf("Generated JWT: %s\n", out);
// Decode the JWT
// ret = jwt_decode(&decoded_jwt, out, (const unsigned char *)secret, strlen(secret));
ret = jwt_decode(&decoded_jwt, out, NULL, 0);
if (ret != 0) {
fprintf(stderr, "Failed to decode JWT");
free(out);
jwt_free(jwt);
return 1;
}
// Access and print the "foo" grant
const char *foo = jwt_get_grant(decoded_jwt, "foo");
if (foo) {
printf("Claim foo: %s\n", foo); // Should print "bar"
} else {
fprintf(stderr, "Claim 'foo' not found\n");
}
// Clean up
free(out);
jwt_free(jwt);
jwt_free(decoded_jwt);
return 0;
}
Running this produces:
Generated JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.S_fQAxWX7eCbvrBlN0wfbxmXoZxFL9EWaeJGj5gj4yE
Claim foo: bar
I believe this happens because, when we do json_decode
, we overwrite (*jwt)->headers
with a fresh json_object
due to a call to jwt_parse
in jwt_decode
which calls jwt_new
: https://github.com/benmcollins/libjwt/blob/master/libjwt/jwt.c#L663 and https://github.com/benmcollins/libjwt/blob/master/libjwt/jwt.c#L619
from libjwt.
Can you give me insight on what you're expecting to happen vs. what is actually happening?
from libjwt.
Expected: jwt_decode
should correctly set decoded_jwt->alg
to jwt->alg
based on the alg
header in the encoded jwt string out
. This was specified by jwt_set_alg(jwt
.
Actual: jwt_decode
discards the alg
header when it calls jwt_parse
because jwt_parse
calls jwt_new
before it calls jwt_parse_head
which then sets ->alg
from the "new" jwt whcih has a blank alg header property: https://github.com/benmcollins/libjwt/blob/master/libjwt/jwt.c#L557-L559
from libjwt.
It's not apparent in your example code where this is happening. One thing I can say is that result of jwt_decode()
is not meant to be reused to create a new JWT without first calling jwt_set_alt()
on the result. The alg and secrets are thrown away on purpose to preserve cryptographic cleanliness. One would expect that since you decoded it, you already know the ALG since you had to know it to decode it.
from libjwt.
It's not apparent in your example code where this is happening. One thing I can say is that result of
jwt_decode()
is not meant to be reused to create a new JWT without first callingjwt_set_alt()
on the result. The alg and secrets are thrown away on purpose to preserve cryptographic cleanliness. One would expect that since you decoded it, you already know the ALG since you had to know it to decode it.
It is not guaranteed that jwts being sent to a server were produced by that server.
Additionally, running jwt_encode_str
on the decoded jwt produces a different jwt string. For reference, the string generated with the alg header set is eyJhbGciOiJIUzI1NiIsImZvbyI6ImJhciIsInR5cCI6IkpXVCJ9.e30.d9cuDlBG72AqPLBKBYNku2CHMNMD3iany8FAhXYB3Bg
, while the jwt string without the alg header is eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJmb28iOiJiYXIifQ.
. If this is expected behavior, it is important to note for users using libjwt that decoding/encoding jwts is not an idempotent process.
Finally, it is not a guarantee that a program generating jwts with libjwt will only ever issue jwts with one algorithm.
Edit: Additionally, this occurs in jwt_parse
when we first run jwt_new
, then we attempt to jwt_parse_head
on the "new" jwt https://github.com/benmcollins/libjwt/blob/master/libjwt/jwt.c#L619-L624
jwt_parse_head attempts to set jwt->alg https://github.com/benmcollins/libjwt/blob/master/libjwt/jwt.c#L558, but it tries to set it from the headers
property of the "new" jwt: https://github.com/benmcollins/libjwt/blob/master/libjwt/jwt.c#L557
from libjwt.
First off, encoded strings are not guaranteed to be the same. This requires sorting all of the claims and other fields in the JWT, which is neither required nor needed by the JWT spec. Relying on this to be guaranteed is broken. Even if you sort the grants and header fields, some algorithms do not produce the same result even for the same input.
I'm still not understanding your workflow here enough to know how to help you with this, but maybe this function can help:
/**
* Like jwt_decode(), but the key will be obtained via the key provider.
* Key providers may use all sorts of key management techniques, e.g.
* can check the "kid" header parameter or download the key pointed to
* in "x5u"
*
* @param jwt Pointer to a JWT object pointer. Will be allocated on
* success.
* @param token Pointer to a valid JWT string, null terminated.
* @param key_provider Pointer to a function that will obtain the key for the given JWT.
* Returns 0 on success or any other value on failure.
* In the case of an error, the same error value will be returned to the caller.
* @return 0 on success, valid errno otherwise.
*
* @remark See jwt_decode()
*/
JWT_EXPORT int jwt_decode_2(jwt_t **jwt, const char *token, jwt_key_p_t key_provider);
It will allow you to inspect the jwt_t
(e.g. the algorithm) and determine what key needs to be used to validate the token.
from libjwt.
It appears that RFC 7519 specifies that the header "alg" is used to specify the algorithm used: https://datatracker.ietf.org/doc/html/rfc7519#section-3.1
Are you sure it makes sense not to set the alg property on the decoded jwt_t from the encoded jwt string? This would mean libjwt loses data integrity.
Edit: As a workaround, code using libjwt to decode jwts could conceivably do jwt->alg = jwt_str_alg(jwt_get_header(decoded_jwt, "alg"))
after they run jwt_decode
.
Edit edit: Consider also that "downstream" code shouldn't need to know whether a jwt_t
was produced using jwt_new
+jwt_set_alg
vs json_decode
.
from libjwt.
I have found where this happens. Inside of jwt_verify_head, we run jwt_scrub_head
(which sets the alg to none https://github.com/benmcollins/libjwt/blob/master/libjwt/jwt.c#L191) if key
is not present on the jwt_t
. Since we are decoding the jwt, the key will not be present on the object. https://github.com/benmcollins/libjwt/blob/master/libjwt/jwt.c#L574
from libjwt.
I've explained that the ALG is not set unless there is a key with it. We do not store the key in a decoded jwt_t
because that would mean we need to copy the secret, and could possibly leak cryptographic information.
Can you explain a workflow that would need this to be kept in the jwt_t
after decoding? If not, I can't help you out.
from libjwt.
It appears that RFC 7519 specifies that the header "alg" is used to specify the algorithm used:
That's correct. HOWEVER, a jwt_t
is NOT a JWT. It is an abstract object used to store data until a JWT is created. You can't apply RFC requirements to an abstract programming object.
from libjwt.
I understand. Thank you for your time and for providing this library. One final thought: since you only ever use jwt_verify_head
in the two decode functions, there will never be a key
in the jwt header. Thus, you could potentially remove that if
inside of the if
as well as the else
in jwt_verify_head
so that it looks like this:
static int jwt_verify_head(jwt_t *jwt)
{
int ret = 0;
if (jwt->alg != JWT_ALG_NONE) {
jwt_scrub_key(jwt);
}
return ret;
}
from libjwt.
Related Issues (20)
- config.h is missing HOT 1
- Setup libjwt and JWT auth on existing HPC Cluster installed from OpenHPC Repo generate errors HOT 9
- OpenSSL 3? HOT 2
- NEWS file? HOT 3
- Compile error in C++ code HOT 3
- jansson.h is missing HOT 4
- Compiling under SSL 3.x triggers warnings. HOT 4
- fatal error: jwt.h: No such file or directory HOT 2
- missing `libjwt-1.15.3.tar.gz` for 1.15.3 release HOT 1
- JWT: jwt_encode_str() function return only three characters. HOT 4
- jwt_decode returns 22 HOT 81
- ./confugre not working HOT 1
- Correct package on Debian 12 HOT 6
- Is 1.16.0 stable? HOT 2
- Upgrade `m4/doxygen.m4` to `ax_prog_doxygen.m4` from GNU Autoconf Archive? HOT 2
- Failed to parse JWT HOT 1
- Error parsing fractional values in JWT exp HOT 3
- Native windows build HOT 1
- finalize mbedTLS support HOT 2
- Building 1.17.0 fails on aarch64
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from libjwt.