#[cfg(feature = "openssl")]
use axum::{
extract::State,
response::{IntoResponse, Json},
routing::get,
Router,
};
#[cfg(feature = "openssl")]
use jwtk::{
jwk::{JwkSet, WithKid},
rsa::RsaAlgorithm,
sign, HeaderAndClaims, PublicKeyToJwk, SomePrivateKey,
};
#[cfg(feature = "openssl")]
use std::{sync::Arc, time::Duration};
#[cfg(feature = "openssl")]
struct AppState {
k: WithKid<SomePrivateKey>,
jwks: JwkSet,
}
#[cfg(feature = "openssl")]
async fn jwks_handler(state: State<Arc<AppState>>) -> impl IntoResponse {
Json(&state.jwks).into_response()
}
#[cfg(feature = "openssl")]
async fn token_handler(state: State<Arc<AppState>>) -> impl IntoResponse {
let mut token = HeaderAndClaims::new_dynamic();
token
.set_iss("me")
.set_sub("you")
.add_aud("them")
.set_exp_from_now(Duration::from_secs(300))
.insert("foo", "bar");
let token = sign(&mut token, &state.k).unwrap();
Json(serde_json::json!({
"token": token,
}))
}
#[cfg(feature = "openssl")]
#[tokio::main]
async fn main() -> jwtk::Result<()> {
let k = std::fs::read("key.pem")?;
let k = SomePrivateKey::from_pem(
&k,
match std::env::var("RSA_ALGO").as_deref() {
Ok(alg) => RsaAlgorithm::from_name(alg)?,
_ => RsaAlgorithm::RS256,
},
)?;
let k = WithKid::new_with_thumbprint_id(k)?;
println!("using key {:?}", k);
let k_public_jwk = k.public_key_to_jwk()?;
let jwks = JwkSet {
keys: vec![k_public_jwk],
};
let state = Arc::new(AppState { k, jwks });
let app = Router::new()
.route("/jwks", get(jwks_handler))
.route("/token", get(token_handler))
.with_state(state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
Ok(())
}
#[cfg(not(feature = "openssl"))]
fn main() {
eprintln!("This example requires the 'openssl' feature");
}