Expand description
Provides JWT (JSON Web Token) authentication support for the Salvo web framework.
This crate helps you implement JWT-based authentication in your Salvo web applications. It offers flexible token extraction from various sources (headers, query parameters, cookies, etc.) and multiple decoding strategies.
§Features
- Extract JWT tokens from multiple sources (headers, query parameters, cookies, forms)
- Configurable token validation
- OpenID Connect support (behind the
oidcfeature flag) - Seamless integration with Salvo’s middleware system
§Crypto Providers
Enable exactly one provider feature in normal builds: aws-lc-rs (the
default) or ring for RustCrypto. If dependency feature unification enables
both providers, call install_crypto_provider at the start of main,
before any JWT operation. This includes validation performed internally by
JwtAuth, ConstDecoder, or OidcDecoder, as well
as direct jsonwebtoken encode or decode calls.
§Security Considerations
Warning: avoid passing JWT tokens in URL query parameters in production.
While this crate supports extracting tokens from query parameters (via QueryFinder),
this method has significant security risks:
- Browser history exposure: URLs with tokens are stored in browser history
- Server logs: Tokens may be logged in web server access logs
- Referer header leakage: Tokens can leak to third-party sites via the Referer header
- Shoulder surfing: Tokens are visible in the address bar
Recommended alternatives:
- Use
HeaderFinderwith theAuthorization: Bearer <token>header (recommended) - Use
CookieFinderwithHttpOnlyandSecurecookie flags
The example below uses the Authorization header via HeaderFinder.
§Example:
use jsonwebtoken::{self, EncodingKey};
use salvo::http::{Method, StatusError};
use salvo::jwt_auth::{ConstDecoder, HeaderFinder, install_crypto_provider};
use salvo::prelude::*;
use serde::{Deserialize, Serialize};
use time::{Duration, OffsetDateTime};
const SECRET_KEY: &str = "YOUR_SECRET_KEY"; // In production, use a secure key management solution
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct JwtClaims {
username: String,
exp: i64,
}
#[tokio::main]
async fn main() {
install_crypto_provider()
.expect("install the JWT crypto provider before first use");
let auth_handler: JwtAuth<JwtClaims, _> = JwtAuth::new(ConstDecoder::from_secret(SECRET_KEY.as_bytes()))
.finders(vec![Box::new(HeaderFinder::new())])
.force_passed(true);
let acceptor = TcpListener::new("0.0.0.0:8698").bind().await;
Server::new(acceptor)
.serve(Router::with_hoop(auth_handler).goal(index))
.await;
}
#[handler]
async fn index(req: &mut Request, depot: &mut Depot, res: &mut Response) -> anyhow::Result<()> {
if req.method() == Method::POST {
let (username, password) = (
req.form::<String>("username").await.unwrap_or_default(),
req.form::<String>("password").await.unwrap_or_default(),
);
if !validate(&username, &password) {
res.render(Text::Html(LOGIN_HTML));
return Ok(());
}
let exp = OffsetDateTime::now_utc() + Duration::days(14);
let claim = JwtClaims {
username,
exp: exp.unix_timestamp(),
};
let token = jsonwebtoken::encode(
&jsonwebtoken::Header::default(),
&claim,
&EncodingKey::from_secret(SECRET_KEY.as_bytes()),
)?;
res.render(Text::Plain(format!(
"Use this token as `Authorization: Bearer {token}`"
)));
} else {
match depot.jwt_auth_state() {
JwtAuthState::Authorized => {
let data = depot.jwt_auth_data::<JwtClaims>().unwrap();
res.render(Text::Plain(format!(
"Hi {}, you have logged in successfully!",
data.claims.username
)));
}
JwtAuthState::Unauthorized => {
res.render(Text::Html(LOGIN_HTML));
}
JwtAuthState::Forbidden => {
res.render(StatusError::forbidden());
}
}
}
Ok(())
}
fn validate(username: &str, password: &str) -> bool {
// In a real application, use secure password verification
username == "root" && password == "pwd"
}
static LOGIN_HTML: &str = r#"<!DOCTYPE html>
<html>
<head>
<title>JWT Auth Demo</title>
</head>
<body>
<h1>JWT Auth</h1>
<form action="/" method="post">
<label for="username"><b>Username</b></label>
<input type="text" placeholder="Enter Username" name="username" required>
<label for="password"><b>Password</b></label>
<input type="password" placeholder="Enter Password" name="password" required>
<button type="submit">Login</button>
</form>
</body>
</html>
"#;Re-exports§
pub use jsonwebtoken::Algorithm;pub use jsonwebtoken::DecodingKey;pub use jsonwebtoken::TokenData;pub use jsonwebtoken::Validation;pub use jsonwebtoken::decode;pub use jsonwebtoken::errors::Error as JwtError;pub use oidc::OidcDecoder;oidc
Modules§
- oidc
oidc - OIDC (OpenID Connect) support.
Structs§
- Const
Decoder - A decoder that uses a constant key for JWT token validation.
- Cookie
Finder - Extracts JWT tokens from cookies.
- Form
Finder - Extracts JWT tokens from request form data.
- Header
Finder - Extracts JWT tokens from HTTP request headers.
- JwtAuth
- JWT Authentication middleware for Salvo.
- Query
Finder - Extracts JWT tokens from URL query parameters.
Enums§
- JwtAuth
Error - JwtAuthError
- JwtAuth
State - Possible states of JWT authentication.
Constants§
- JWT_
AUTH_ DATA_ KEY - key used to insert auth decoded data to depot.
- JWT_
AUTH_ ERROR_ KEY - key used to insert auth error to depot.
- JWT_
AUTH_ STATE_ KEY - key used to insert auth state data to depot.
- JWT_
AUTH_ TOKEN_ KEY - key used to insert auth token data to depot.
Traits§
- JwtAuth
Decoder - Trait for JWT token decoding and validation.
- JwtAuth
Depot Ext - Extension trait for accessing JWT authentication data from the depot.
- JwtToken
Finder - Trait for extracting JWT tokens from HTTP requests.
Functions§
- install_
crypto_ provider - Installs the crypto provider selected by this crate for the current process.