Replies: 2 comments 2 replies
-
Cool, thanks for writing up your use case, I'll try and quote and reply to some bits of it...
okey, yep, that's not too unusual I think - in particular it's quite common for the
So I suppose I wonder if this is done with an entirely non-standard payload for the token, or maybe you put your custom type fields inside your
For destructuring it's hopefully possible to do something like this: use serde_json::value::Value;
let TokenSlices {message, signature, header, claims } = raw::split_token(token)?;
let header: Value = raw::decode_json_token_slice(header)?;
let claims: Value = raw::decode_json_token_slice(claims)?; I suppose since this is a more manual break down and verify route I'm not quite sure it can be reduced much more but depending on what you do with the claims/header the type might be inferred. Were you thinking it'd be nice to somehow reduce this even further?
Right, this should hopefully be possible to avoid - funnily enough one of the reasons I ended up making jsonwebtokens in the first place was because I was a bit annoyed with having to parse the tokens multiple times for my use case with other libs :) Since you're needing to manually split your token and decode the different parts then you can use the A completely manual split; decode of parts; signature verification and claims verification could look something like: let alg = Algorithm::new_hmac(AlgorithmID::HS256, "secret")?;
let verifier = Verifier::create()
// snip
.build()?;
let TokenSlices {message, signature, header, claims } = raw::split_token(token)?;
let header = raw::decode_json_token_slice(header)?;
raw::verify_signature_only(&header, message, signature, &alg)?;
let claims = raw::decode_json_token_slice(claims)?;
verifier.verify_claims_only(&claims, time_now)?; With the enum structure and needing to check the enum type for completing verification, I'm not currently sure whether you'd be wanting to handle verifying those as a separate step after verifying standard claims, or maybe your enum type even affects how you want to verify standard claims too? I could certainly imagine wanting some final custom steps with something like <snip>
verifier.verify_claims_only(&claims, time_now)?;
let custom: MyClaims = serde_json::from_value(&claims);
let ok = match custom.my_type {
... extra verification depending on enum type
} I can see how the Verifiers customization api is not going to be really well suited to handling the dependency on the enum type here. Currently The most flexible escape hatch is the If your enum type should affect verifying standard claims then I guess, hopefully its not too many secret+enum-type combinations and I suppose you define a seperate Verifier for each combo. In that case your (secret,enum-type) could act like a key for finding the right Verifier you need and those are the only two bits of information your read before verifying claims (besides checking the signature).
This is a tricky detail perhaps. It was a conscious decision to be very explicit about what algorithm is used considering that there have been a number of security exploits documented as a result of automatic algorithm inference. There are two notable traps that come to mind for libraries that might try and infer/detect the algorithm:
These were two notable dangers I found documented in the wild and so thought it would be worth designing this so you have to specify your algorithm (conceptually nothing about the JWT should be considered trusted until the signature is verified so it seems good to minimize what influence it may have over how you verify a token) In your situation you may even want to double/tripple check just in case you might be ending up in a risky space by using the embedded Hopefully with this background this design choice makes sense, but I also might not have fully followed the nuance of your use case to know if there could still be a case for auto selection in some case (I'm not exactly sure what it means to let users change the signature without invalidating a token). I'm aware that some libraries such as
If possible, it sounds like it could be good to use the standard Based on the thoughts, above I'd be quite worried about the combination of
Yeah, this relates to one of the reasons I essentially ended up diverging from jsonwebtoken (without an 's') it's easy to paint into a corner where you're forced to double parse. My general design principle had been to provide a high level api for common cases which can handle all the destructuring and verification itself and finally also deserialize to any custom struct you have if wanted, but for more manual stuff, then it works with So to clarify; you can decode an unverified token into whatever type you like (the decode apis are generic and will rely on type inference to determine what to deserialize into) - but if you end up needing the raw apis for more manual use cases then they basically require you to start out by destructuring / deserializing into Value, but you could always choose to additionally deserialize into a custom type for some extra verification steps and wouldn't really be penalized from the pov that we needed the Value at the very least anyway as a lowest common denominator that jsonwebtokens works with internally.
I think this should be possible with the current api, e.g. I think you should be able to do something like: let TokenSlices {message, signature, header, claims } = raw::split_token(token)?;
struct MyCustomClaims {
foo: u32
}
let claims = raw::decode_json_token_slice(claims)?; or rather I suppose you mean you just want your custom/concrete type at the end, and in that case the 'intermediate' type would be a Thanks again for summarising your use case. I can see how the conditional verification based on your token type adds some extra complexity where it's maybe not obvious if it's best to handle that using the Verifier api or maybe handle as a step afterwards - I guess the main decider might be whether the type affects verification of standard claims. I have a feeling that with something like this I'd maybe try and use the standard Hope a few of my rambling thoughts/pointers make sense here. :) (let me know if not) I think the main thing it's got me pondering about is whether there's a practical way to help with conditional claim verification - like with your enum type. Off the top of my head I think it could easily get out of hand for the Verifier api to really get overly flexible/complex but maybe there's another kind of simple escape hatch that could be added to help with that kind of thing. |
Beta Was this translation helpful? Give feedback.
-
While reading your response I realized that I might not have been clear. You are completely right in what you say, and the availability of the low level API is why I went with Oh, after reading what you wrote, the design makes actually a lot of sense. So, my takeaways:
Thanks for your time and insight and let's see if I can up the efficiency of my code :) Late edit: I was actually able to refactor my code to a reasonably clean version, just by using the |
Beta Was this translation helpful? Give feedback.
-
Hi!
Let me try to describe how I misuse
jsonwebtokens
. Unfortunately I can't share the source code directly, but I think I can describe it. Now, this is rather low priority, but I hope some of these points may give you some idea how other people (mis)usejsonwebtokens
.My use case
I'm perhaps misusing JWT, but I store a different secret for each of my tokens. This means I need to look the secret up with every token validation.
I also store a token type (in fact, my token is an enum with different fields for each variant). This means I need to build different verifier objects depending on the data itself.
I solve this currently by slicing the input token up with
split_token()
, I decode (withdecode_json_token_slice
and decoding withserde_json
) the header to get the signature algo, decode the claims to get the token's unique id and look up the secret. I could probably put the id into the header, but that's a different question.After this, I look up the token secret and I verify the whole token with a
Verifier
instance.My problems with what I need to do:
invalidating issued tokens,
jsonwebtokens
could/should probably detect the algo automatically, maybe even by default.Alternatives
I have some alternative usage patterns in mind, that may be more elegant in my case:
1: Let me look up the secret in the verifier. It's still not ideal for me (I actually need to build different verifiers based on some token property), but it probably is for others:
2: Let me decode an unverified token into whatever my type is, and let theJust as I write this, I realized this is pretty hard to do without deserializing the token twice.Verifier
verify that.2, again: let me decode an unverified token into an intermediate type I can work with, then let the
Verifier
verify that and decode into my concrete type.Beta Was this translation helpful? Give feedback.
All reactions