From bbb58d91ba1a442aef78ec6e8f8bcdca5e0e353b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 15:47:42 +0000 Subject: [PATCH 1/2] Initial plan From 60f61a45ab91d454b13e7a562355457b9d67d1ea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 15:49:19 +0000 Subject: [PATCH 2/2] docs: fix JWT auth recipe and quickstart based on review comments Co-authored-by: Tuntii <121901995+Tuntii@users.noreply.github.com> --- .../src/getting_started/quickstart.md | 2 +- docs/cookbook/src/recipes/jwt_auth.md | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/cookbook/src/getting_started/quickstart.md b/docs/cookbook/src/getting_started/quickstart.md index be92f98b..df81d4db 100644 --- a/docs/cookbook/src/getting_started/quickstart.md +++ b/docs/cookbook/src/getting_started/quickstart.md @@ -12,7 +12,7 @@ cargo rustapi new my-api cd my-api ``` -This commands sets up a complete project structure with handling, models, and tests ready to go. +This command sets up a complete project structure with handling, models, and tests ready to go. ## The Code diff --git a/docs/cookbook/src/recipes/jwt_auth.md b/docs/cookbook/src/recipes/jwt_auth.md index 0d0c53e7..63e83c69 100644 --- a/docs/cookbook/src/recipes/jwt_auth.md +++ b/docs/cookbook/src/recipes/jwt_auth.md @@ -21,9 +21,9 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Claims { - pub sub: String, // Subject (User ID) - pub role: String, // Custom claim: "admin", "user" - // 'exp' is handled automatically by the framework if not present + pub sub: String, // Subject (User ID) + pub role: String, // Custom claim: "admin", "user" + pub exp: usize, // Required for JWT expiration validation } ``` @@ -56,14 +56,21 @@ async fn protected_profile( #[rustapi::post("/login")] async fn login(State(state): State) -> Result> { // In a real app, validate credentials first! + use std::time::{SystemTime, UNIX_EPOCH}; + + let expiration = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() + 3600; // Token expires in 1 hour (3600 seconds) + let claims = Claims { sub: "user_123".to_owned(), role: "admin".to_owned(), + exp: expiration as usize, }; - // Create a token that expires in 1 hour (3600 seconds) // We use the secret from our shared state - let token = create_token(&claims, &state.secret, 3600)?; + let token = create_token(&claims, &state.secret)?; Ok(Json(token)) } @@ -74,7 +81,7 @@ async fn login(State(state): State) -> Result> { Register the `JwtLayer` and the state in your application. ```rust -#[tokio::main] +#[rustapi::main] async fn main() -> Result<()> { // In production, load this from an environment variable! let secret = "my_secret_key".to_string(); @@ -84,8 +91,7 @@ async fn main() -> Result<()> { }; // Configure JWT validation with the same secret - let jwt_layer = JwtLayer::new(secret) - .with_algorithm(jsonwebtoken::Algorithm::HS256); + let jwt_layer = JwtLayer::::new(secret); RustApi::auto() .state(state) // Register the shared state