axum_jwt/decode.rs
1use {
2 axum_core::extract::FromRef,
3 jsonwebtoken::{DecodingKey, TokenData, Validation},
4 serde::de::DeserializeOwned,
5 std::{fmt, ops::Deref, sync::Arc},
6};
7
8/// A decoder for JSON Web Tokens (JWTs).
9///
10/// To extract a JWT value from a request header, this decoder must be provided
11/// to the [router] using the [`with_state`] method.
12///
13/// [router]: https://docs.rs/axum/latest/axum/struct.Router.html
14/// [`with_state`]: https://docs.rs/axum/latest/axum/struct.Router.html#method.with_state
15///
16/// # Examples
17///
18/// You can pass the decoder directly:
19///
20/// ```
21/// use {
22/// axum::{Router, routing},
23/// axum_jwt::{Claims, Decoder, jsonwebtoken::DecodingKey},
24/// serde::Deserialize,
25/// };
26///
27/// #[derive(Deserialize)]
28/// struct User {
29/// sub: String,
30/// }
31///
32/// async fn hello(Claims(u): Claims<User>) -> String {
33/// format!("Hello, {}!", u.sub)
34/// }
35///
36/// let decoder = Decoder::from_key(DecodingKey::from_secret(b"secret"));
37///
38/// let app = Router::new()
39/// .route("/", routing::get(hello))
40/// .with_state(decoder);
41/// # let _: Router = app;
42/// ```
43///
44/// If the application needs to store additional state, you can define a custom
45/// type that contains the decoder. You'll also need the application state to
46/// be cheap to clone, so it makes sense to wrap it in an [`Arc`]. In this
47/// case, you can provide the decoder by implementing the [`AsRef`] trait for
48/// your custom state.
49///
50/// ```
51/// # use {
52/// # axum::{Router, routing},
53/// # axum_jwt::{Decoder, jsonwebtoken::DecodingKey},
54/// # std::sync::{Arc, Mutex},
55/// # };
56/// # struct User;
57/// struct App {
58/// decoder: Decoder,
59/// users_online: Mutex<Vec<User>>,
60/// }
61///
62/// impl AsRef<Decoder> for App {
63/// fn as_ref(&self) -> &Decoder {
64/// &self.decoder
65/// }
66/// }
67///
68/// let decoder = Decoder::from_key(DecodingKey::from_secret(b"secret"));
69///
70/// # async fn hello() {}
71/// let app = Router::new()
72/// .route("/", routing::get(hello))
73/// .with_state(Arc::new(App {
74/// decoder,
75/// users_online: Mutex::default(),
76/// }));
77/// # let _: Router = app;
78/// ```
79#[derive(Clone)]
80pub struct Decoder(Arc<Inner>);
81
82impl Decoder {
83 /// Creates a decoder from the provided decoding key.
84 pub fn from_key(key: DecodingKey) -> Self {
85 Self(Arc::new(Inner {
86 keys: vec![key],
87 validation: Validation::default(),
88 }))
89 }
90
91 /// Creates a decoder from the provided decoding key and validation.
92 pub fn new(key: DecodingKey, validation: Validation) -> Self {
93 Self(Arc::new(Inner {
94 keys: vec![key],
95 validation,
96 }))
97 }
98
99 /// Creates a decoder from the provided decoding keys and validation.
100 ///
101 /// If the given vector is empty, this constructor will return `None`.
102 pub fn with_keys(keys: Vec<DecodingKey>, validation: Validation) -> Option<Self> {
103 if keys.is_empty() {
104 None
105 } else {
106 Some(Self(Arc::new(Inner { keys, validation })))
107 }
108 }
109
110 /// Returns a slice of decoding keys.
111 pub fn keys(&self) -> &[DecodingKey] {
112 &self.0.keys
113 }
114
115 /// Returns a reference to the validation.
116 pub fn validation(&self) -> &Validation {
117 &self.0.validation
118 }
119
120 pub(crate) fn decode<T>(&self, token: &str) -> Result<TokenData<T>, jsonwebtoken::errors::Error>
121 where
122 T: DeserializeOwned,
123 {
124 let decoder = &*self.0;
125 let mut err = None;
126 for key in &decoder.keys {
127 match jsonwebtoken::decode(token, key, &decoder.validation) {
128 Ok(data) => return Ok(data),
129 Err(e) => err = Some(e),
130 }
131 }
132
133 Err(err.expect("take error"))
134 }
135}
136
137impl fmt::Debug for Decoder {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 f.debug_struct("Decoder")
140 .field("keys", &"..")
141 .field("validation", &self.0.validation)
142 .finish()
143 }
144}
145
146impl<P> FromRef<P> for Decoder
147where
148 P: Deref<Target: AsRef<Self>>,
149{
150 fn from_ref(p: &P) -> Self {
151 p.as_ref().clone()
152 }
153}
154
155struct Inner {
156 keys: Vec<DecodingKey>,
157 validation: Validation,
158}