7 releases (breaking)
0.8.0 | Aug 16, 2024 |
---|---|
0.7.0 | Mar 14, 2024 |
0.6.2 | Jan 29, 2024 |
0.5.0 | Aug 28, 2023 |
0.2.0 | Mar 29, 2023 |
#592 in Authentication
278 downloads per month
21KB
281 lines
axum-jwks
Use a JSON Web Key Set (JWKS) to verify JWTs in Axum.
Features
- Use an openid-configuration to get the setup from the Authorization Server.
- Pull a JWKS directly from an Authorization Server
- Verify JWTs signed by any key in the JWKS and provided as a bearer token in
the
Authorization
header
For more information, see the crate documentation.
lib.rs
:
axum-jwks allows for easily verifying JWTs in an axum application using any key from a JSON Web Key Set (JWKS).
Usage
Here's a minimal working example of how you would authenticate via JWTs in a route handler:
use axum::{
async_trait,
extract::{FromRef, FromRequestParts},
http::request::Parts,
http::status::StatusCode,
response::{IntoResponse, Response},
routing::get,
Json,
Router,
};
use axum_jwks::{Claims, Jwks, ParseTokenClaims, TokenError};
use serde::{Deserialize, Serialize};
// The state available to all your route handlers.
#[derive(Clone)]
struct AppState {
jwks: Jwks,
}
impl FromRef<AppState> for Jwks {
fn from_ref(state: &AppState) -> Self {
state.jwks.clone()
}
}
// The specific claims you want to parse from received JWTs.
#[derive(Deserialize, Serialize)]
struct TokenClaims {
pub sub: String
}
impl ParseTokenClaims for TokenClaims {
type Rejection = TokenClaimsError;
}
enum TokenClaimsError {
Missing,
Invalid,
}
impl IntoResponse for TokenClaimsError {
fn into_response(self) -> Response {
// You could do something more informative here like providing a
// response body with different error messages for missing vs.
// invalid tokens.
StatusCode::UNAUTHORIZED.into_response()
}
}
impl From<TokenError> for TokenClaimsError {
fn from(value: TokenError) -> Self {
match value {
TokenError::Missing => Self::Missing,
other => Self::Invalid,
}
}
}
// Handler that echos back the claims it receives. If the handler receives
// these claims, it's guaranteed that they come from a JWT that is signed
// by a key from the JWKS and is valid for the specified audience.
async fn echo_claims(Claims(claims): Claims<TokenClaims>) -> Json<TokenClaims> {
Json(claims)
}
async fn create_router() -> Router<AppState> {
let jwks = Jwks::from_oidc_url(
// The Authorization Server that signs the JWTs you want to consume.
"https://my-auth-server.example.com/.well-known/openid-configuration",
// The audience identifier for the application. This ensures that
// JWTs are intended for this application.
Some("https://my-api-identifier.example.com/"),
)
.await
.unwrap();
Router::new()
.route("/echo-claims", get(echo_claims))
.with_state(AppState { jwks })
}
Dependencies
~14–27MB
~498K SLoC