JWT Auth Middleware (Rust)
Topics: HMAC-SHA256, base64url, JSON, middleware (Service/Layer)
Problem
Implement a minimal HS256 JWT signer/verifier and an auth middleware that enforces it. The
crypto uses the hmac + sha2 crates; the middleware is a hand-written, synchronous version of the
Service / Layer pattern that every Rust HTTP stack (tower, axum, hyper) is built on — so you
implement the mechanism itself, not a framework's API.
pub struct Claims { pub sub: String, pub exp: i64, pub nbf: i64 }
pub enum JwtError { Malformed, InvalidSignature, Expired, NotYetValid }
pub fn sign(claims: &Claims, secret: &[u8]) -> Result<String, JwtError>;
pub fn verify(token: &str, secret: &[u8]) -> Result<Claims, JwtError>;
pub trait Service { fn call(&self, req: Request) -> Response; }
pub trait Layer<S> { type Service; fn layer(&self, inner: S) -> Self::Service; }
pub struct AuthLayer { /* … */ } // AuthLayer::new(secret).layer(handler)
sign → base64url(header).base64url(payload).base64url(HMAC-SHA256(header.payload)).
verify → recompute and constant-time-compare the signature (Mac::verify_slice), then check
exp/nbf (treat 0 as unset). Errors: Malformed, InvalidSignature, Expired,
NotYetValid.
AuthService::call (the middleware) → read Authorization: Bearer <token>, verify it, inject the
Claims into the request, and call the inner service. Missing/invalid/expired → 401.
The Request/Response/Service/Layer/HandlerFn/AuthLayer scaffolding is provided; you write
sign, verify, and AuthService::call.
Key concepts
- Service / Layer: a handler is
Request -> Response; middleware is a Service that wraps
another Service. AuthLayer::new(secret).layer(inner) produces an AuthService — the same
decorator shape tower formalizes (here synchronous, no runtime).
- base64url, no padding: JWT uses URL-safe base64 with
= stripped (URL_SAFE_NO_PAD).
- Constant-time compare:
Mac::verify_slice compares in constant time, avoiding signature
timing leaks.
- Claims injection: instead of Go's request context, the verified
Claims ride on the
Request itself, so the inner handler reads req.claims.
Grading
Your solution.rs is the crate library; it's compiled with the dependencies in Cargo.toml and run
against the trusted tests.rs via cargo test. Only solution.rs is yours to edit.
Sign in to submit your solution.