| Crates.io | jwk-simple |
| lib.rs | jwk-simple |
| version | 0.1.0 |
| created_at | 2026-01-20 22:20:33.915186+00 |
| updated_at | 2026-01-20 22:20:33.915186+00 |
| description | JWK/JWKS support with WASM compatibility and jwt-simple integration |
| homepage | https://github.com/sagikazarmark/jwk-simple |
| repository | https://github.com/sagikazarmark/jwk-simple |
| max_upload_size | |
| id | 2057707 |
| size | 343,464 |
[!WARNING] This project is a work in progress. The API may change.
A Rust library for working with JSON Web Keys (JWK) and JWK Sets (JWKS) as defined in RFC 7517, with WASM compatibility and optional jwt-simple integration.
Add to your Cargo.toml:
[dependencies]
jwk-simple = "0.1"
Parse a JWKS and find a key:
use jwk_simple::KeySet;
let json = r#"{
"keys": [{
"kty": "RSA",
"kid": "my-key-id",
"use": "sig",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"e": "AQAB"
}]
}"#;
let jwks: KeySet = serde_json::from_str(json)?;
let key = jwks.find_by_kid("my-key-id").expect("key not found");
assert!(key.is_public_key_only());
| Feature | Default | Description |
|---|---|---|
jwt-simple |
❌ | Integration with the jwt-simple crate |
http |
❌ | Async HTTP fetching with caching support (reqwest) |
cloudflare |
❌ | Cloudflare Workers KV cache support |
use jwk_simple::{KeySet, KeyType, KeyUse};
// Parse from JSON string
let jwks: KeySet = serde_json::from_str(json)?;
// Find keys by various criteria
let key = jwks.find_by_kid("key-id");
let rsa_keys = jwks.find_by_kty(KeyType::Rsa);
let signing_keys = jwks.find_by_use(KeyUse::Signature);
// Get the first signing key (common pattern)
let first_signing = jwks.first_signing_key();
// Iterate over all keys
for key in &jwks {
println!("Key: {:?}", key.kid);
}
With the jwt-simple feature enabled:
use jwk_simple::KeySet;
use jwt_simple::prelude::*;
let jwks: KeySet = serde_json::from_str(json)?;
let jwk = jwks.find_by_kid("my-key").unwrap();
// Convert to jwt-simple key type using TryFrom/TryInto
let key: RS256PublicKey = jwk.try_into()?;
// Verify a JWT
let claims = key.verify_token::<NoCustomClaims>(&token, None)?;
With the http feature enabled:
use jwk_simple::{KeySource, RemoteKeySet, InMemoryCachedKeySet};
use std::time::Duration;
// Create remote key set (uses default 30s timeout)
let remote = RemoteKeySet::new("https://example.com/.well-known/jwks.json");
// For custom timeout, use a custom client
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(10))
.build()?;
let remote = RemoteKeySet::new_with_client(
"https://example.com/.well-known/jwks.json",
client,
);
// Fetch the JWKS
let jwks = remote.get_keyset().await?;
// For production, wrap with caching (5 minute TTL)
let cached = InMemoryCachedKeySet::with_ttl(
RemoteKeySet::new("https://example.com/.well-known/jwks.json"),
Duration::from_secs(300),
);
let key = cached.get_key("my-key-id").await?;
With the http feature enabled:
use jwk_simple::{InMemoryKeyCache, InMemoryCachedKeySet, KeyCache, KeySource, RemoteKeySet};
use std::time::Duration;
// Create a cached remote key source
let cached = InMemoryCachedKeySet::with_ttl(
RemoteKeySet::new("https://example.com/.well-known/jwks.json"),
Duration::from_secs(300), // 5 minute TTL
);
// Keys are automatically cached on first access
let key = cached.get_key("key-id").await?;
// Invalidate the entire cache when needed
cached.invalidate().await;
// Or invalidate a specific key
cached.invalidate_key("key-id").await;
use jwk_simple::KeySet;
let jwks: KeySet = serde_json::from_str(json)?;
let key = jwks.first().unwrap();
// Calculate thumbprint (base64url-encoded SHA-256)
let thumbprint = key.thumbprint();
// Find key by thumbprint
let key = jwks.find_by_thumbprint(&thumbprint);
| Feature | jwk-simple | jwks-client | jsonwebkey | jwt-simple | jsonwebtoken |
|---|---|---|---|---|---|
| Full JWKS spec | ✅ | ✅ | ❌ | ❌ | ❌ |
| RSA keys | ✅ | ✅ | ✅ | ✅ | ✅ |
| EC keys (P-256/384/521) | ✅ | ⚠️ | ✅ | ✅ | ✅ |
| EdDSA (Ed25519) | ✅ | ❌ | ❌ | ✅ | ✅ |
| Symmetric keys | ✅ | ❌ | ✅ | ✅ | ✅ |
| OKP keys (X25519) | ✅ | ❌ | ❌ | ❌ | ❌ |
| WASM support | ✅ | ❌ | ❓ | ✅ | ❓ |
| jwt-simple integration | ✅ | ❌ | ❌ | N/A | ❌ |
| HTTP fetching | ✅ | ✅ | ❌ | ❌ | ❌ |
| Caching | ✅ | ✅ | ❌ | ❌ | ❌ |
| Zeroize support | ✅ | ❌ | ✅ | ✅ | ❌ |
| No-panic guarantee | ✅ | ✅ | ❌ | ✅ | ❌ |
| JWK thumbprint (RFC 7638) | ✅ | ❌ | ❌ | ❌ | ❌ |
| TryFrom/TryInto traits | ✅ | ❌ | ❌ | ❌ | ✅ |
| Private key support | ✅ | ❌ | ✅ | ✅ | ❌ |
This crate prioritizes security:
zeroize cratebase64ctResult typesCore JWKS parsing works in WebAssembly environments. The following features are NOT available in WASM:
http - No async HTTP in WASM (use browser fetch and pass JSON string)Example for WASM:
use jwk_simple::KeySet;
// In WASM, fetch JWKS via browser APIs, then parse
let jwks: KeySet = serde_json::from_str(&json_string)?;
let key = jwks.find_by_kid("key-id").expect("key not found");
The project is licensed under the MIT License.