rust 66 lines · 8 steps

How a JWT extractor works in Axum

Turning a Claims struct into an Axum extractor that validates a bearer token from the request headers.

Explained by highlit
1use axum::{
2 extract::{FromRef, FromRequestParts},
3 http::{header, request::Parts, StatusCode},
4 RequestPartsExt,
5};
6use axum_extra::{
7 headers::{authorization::Bearer, Authorization},
8 TypedHeader,
9};
10use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
11use serde::{Deserialize, Serialize};
12 
13#[derive(Clone)]
14pub struct JwtConfig {
15 pub decoding_key: DecodingKey,
16 pub validation: Validation,
17}
18 
19#[derive(Debug, Serialize, Deserialize)]
20pub struct Claims {
21 pub sub: String,
22 pub email: String,
23 pub roles: Vec<String>,
24 pub exp: usize,
25}
26 
27pub enum AuthError {
28 MissingToken,
29 InvalidToken,
30}
31 
32impl axum::response::IntoResponse for AuthError {
33 fn into_response(self) -> axum::response::Response {
34 let (status, msg) = match self {
35 AuthError::MissingToken => (StatusCode::UNAUTHORIZED, "missing bearer token"),
36 AuthError::InvalidToken => (StatusCode::UNAUTHORIZED, "invalid or expired token"),
37 };
38 (status, [(header::WWW_AUTHENTICATE, "Bearer")], msg).into_response()
39 }
40}
41 
42impl<S> FromRequestParts<S> for Claims
43where
44 JwtConfig: FromRef<S>,
45 S: Send + Sync,
46{
47 type Rejection = AuthError;
48 
49 async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
50 let TypedHeader(Authorization(bearer)) = parts
51 .extract::<TypedHeader<Authorization<Bearer>>>()
52 .await
53 .map_err(|_| AuthError::MissingToken)?;
54 
55 let config = JwtConfig::from_ref(state);
56 
57 let token_data = decode::<Claims>(
58 bearer.token(),
59 &config.decoding_key,
60 &config.validation,
61 )
62 .map_err(|_| AuthError::InvalidToken)?;
63 
64 Ok(token_data.claims)
65 }
66}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Implementing FromRequestParts lets any type become a handler argument that runs custom logic before the handler.
  2. 2FromRef decouples the extractor from the exact application state shape, requiring only that JwtConfig be extractable from it.
  3. 3Modeling failures as an IntoResponse enum keeps auth errors type-safe while still producing proper HTTP responses.

Related explainers

Share this explainer

Here's the card — post it anywhere.

How a JWT extractor works in Axum — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code