Comments (8)
Hi @naftulikay! In your original message you mentioned that you were going to use jwk_set of public keys, however the solution you provided was for a single jwk, and you created the token_verifier
outside of the selector
closure and referenced it. I am fairly new to rust, and I cannot figure out how to implement something like this that dynamically selects a verifier based on jwk:
let (_verified_claims, _verified_header) =
jwt::decode_with_verifier_in_jwk_set(token, &jwk_set, |jwk| match jwk.algorithm() {
Some("RS256") => Ok(Some(&RS256.verifier_from_jwk(jwk)?)),
Some("P-521") => Ok(Some(&ES512.verifier_from_jwk(jwk)?)),
_ => Ok(None),
})?;
This doesn't work because of cannot return value referencing temporary value returns a value referencing data owned by the current function
.
@hidekatsu-izuno I tried to search the documentation and the tests and couldn't find a usage example for any of the functions that take the selector Fn
.
from josekit-rs.
Thanks @w0rm , but i found https://github.com/lawliet89/biscuit which is a lot easier to use.
Also i cannot rely on KID, as the jwts are user provided.
from josekit-rs.
@w0rm i noticed, but that is not a requirement for me yet. I guess i'll refactor it there when it comes to it.
from josekit-rs.
I was able to solve the issue, full source code available here.
In short:
use josekit::jwk::alg::ed::{EdCurve, EdKeyPair};
use josekit::jwk::{Jwk, KeyPair};
use josekit::jws::alg::eddsa::{EddsaJwsSigner, EdssaJwsVerifier};
use josekit::jws::{EdDSA, JwsHeader};
use josekit::jwt::{self, JwtPayload};
// generate the keypair and its jwk representations
let keypair: EdKeyPair = EdDSA.generate_key_pair(EdCurve::Ed25519).unwrap();
let jwk_keypair: Jwk = keypair.to_jwk_key_pair();
let jwk_public: Jwk = jwk_keypair.to_public_key().unwrap();
// create a token signer using the private key
let token_signer: EddsaJwsSigner = EdDSA.signer_from_jwk(&jwk_keypair).unwrap();
// generate header and claims to sign
let (header, claims): (JwsHeader, JwtPayload) = create_token();
// sign with the private key
let token: String = jwt::encode_with_signer(&claims, &header, &token_signer).unwrap();
// create a verifier
let token_verifier: EddsaJwsVerifier = EdDSA.verifier_from_jwk(&jwk_public).unwrap();
// verify the claims using a selector that chooses a key based on the header's key id
let (_verified_claims, _verified_header) =
jwt::decode_with_verifier_selector(token, |header| {
if let Some(header_key_id) = header.key_id() {
// if the header's key id matches our key's key id, use that as the verifier
if header_key_id == jwk_pub.key_id().unwrap() {
return Ok(Some(&token_verifier));
}
}
Ok(None)
})
.unwrap_or_else(|e| {
eprintln!("Failed to decode/verify token: {}", e);
exit(1)
});
from josekit-rs.
I'm glad you were able to solve the problem. I'm sorry I am too busy to answer your issue.
from josekit-rs.
I'm also looking for a way to universally verify a JWT with any key in the keyset no matter the algorithm.
For now i'll make do with brute forcing all algorithms like this:
pub fn get_jwk_verifier(jwk: &Jwk) -> Option<Box<dyn JwsVerifier>> {
None.or_else(
|| [ES256, ES384, ES512].iter().find_map(|it|it.verifier_from_jwk(jwk).map(Box::<dyn JwsVerifier>::new).ok())
).or_else(
|| [Eddsa].iter().find_map(|it|it.verifier_from_jwk(jwk).map(Box::<dyn JwsVerifier>::new).ok())
)
}
keyset.keys().into_iter().filter_map(get_jwk_verifier).find_map(|v|josekit::jwt::decode_with_verifier(&create.public_keys_jwt, &v).ok())
i think there should be compile time associated const str that can be used to match and build a Box<dyn JwsVerifier>
directly
from josekit-rs.
@Wicpar I've ended up loading a mapping from key id to a verifier:
let jws_verifiers = JwkSet::from_bytes(bytes)?
.keys()
.into_iter()
.filter_map(|jwk| {
let kid = jwk.key_id()?.to_string();
if jwk.key_use() != Some("sig") {
return None;
}
match jwk.key_type() {
"RSA" => Some(RS256.verifier_from_jwk(jwk).map(|v| (kid, v.box_clone()))),
"EC" => Some(ES512.verifier_from_jwk(jwk).map(|v| (kid, v.box_clone()))),
"OKP" => Some(EdDSA.verifier_from_jwk(jwk).map(|v| (kid, v.box_clone()))),
_ => None,
}
})
.collect::<Result<BTreeMap<String, Box<dyn JwsVerifier>>, _>>()?;
And then later I get a verifier by the key id and use it to validate the token:
let (payload, _header) = decode_with_verifier_selector(&token, |header| {
Ok(header
.key_id()
.and_then(|kid| jws_verifiers.get(kid))
.map(|el| el.as_ref()))
})?;
from josekit-rs.
@Wicpar I've just remembered why I didn't go with biscuit, it is because I needed ES512
, that is not supported: https://github.com/lawliet89/biscuit/blob/0333da5a60f626d418d5575324a353c5eae1dc51/src/jwa.rs#L100
from josekit-rs.
Related Issues (17)
- Only decode header HOT 2
- set_x509_certificate_chain (x5c) implementation is wrong HOT 3
- JWS with x5c header parameter HOT 7
- x509_certificate_chain must be encoded in STANDARD, not URL_SAFE_NO_PAD or STANDARD_NOPAD HOT 1
- Jws/JweHeaderSet critical value should not be encoded by BASE64 HOT 1
- RUSTSEC-2023-0022 to 0024 => security advisory on openssl HOT 1
- Support the `ECMR` operation for JWK exchange HOT 2
- Allow to enable openssl vendored feature to cross compile HOT 4
- How to get verifier from algorithm name or JWK HOT 4
- An equivalent function to node-jose's createEncrypt
- Security vulnerability disclosure HOT 3
- Support for Brainpool curves HOT 2
- Wrong iv length in JWE header HOT 3
- [QUESTION] how to properly use decode_with_verifier_in_jwk_set HOT 4
- [QUESTION] How can I cast JoseHeader to JwsHeader? HOT 1
- Allow deserialization of JwtPayload HOT 2
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 josekit-rs.