Why Rust is the Ideal Choice for Authentication?
\n\nIf you are writing a web application in Rust, you are already one step ahead in terms of security. Rust does not forgive memory errors, meaning many vulnerabilities (buffer overflow, use-after-free) are eliminated at compile time. But the compiler will not protect you from poor authentication logic. That is what this is about — how to build secure authentication in Rust using modern practices.
\n\nIn this article, we will assemble a full-fledged authentication module: password hashing via bcrypt, JWT token issuance, middleware verification in Actix-web, and protection against common attacks. The code will be functional — feel free to use it in your project.
1. Password Hashing: Why bcrypt and Not SHA-256?
\n\nMany beginners think: "I'll use SHA-256, it's fast and reliable." And that is a fatal mistake. SHA is a cryptographic hash function, but it is too fast. An attacker can brute-force billions of combinations per second. We need a slow function, specifically designed for passwords.
\n\nbcrypt is the gold standard. It includes a salt and a cost factor, which can be increased as computing power grows.
\n\nAdding bcrypt to Cargo.toml
\n[dependencies]\nbcrypt = "0.15"\n\nHashing a Password
\nuse bcrypt::{hash, verify, DEFAULT_COST};\n\nfn hash_password(plain: &str) -> Result<String, bcrypt::BcryptError> {\n hash(plain, DEFAULT_COST) // cost = 12 (default)\n}\n\nfn verify_password(plain: &str, hashed: &str) -> bool {\n verify(plain, hashed).unwrap_or(false)\n}\n\nNote: verify extracts the salt from the hash itself. You do not need to store the salt separately — it is already inside the hash string. This is safe and convenient.
2. JWT Tokens: How Not to Fail Authentication
\n\nAfter the user enters their password, we must issue them a "pass". JWT (JSON Web Token) is a compact and self-contained format. But the devil is in the details:
\n\n- \n
- Do not store the secret key in code. Use environment variables. \n
- Set a short expiration time. Access token — 15–30 minutes, refresh token — 7–30 days. \n
- Do not insert sensitive data into the payload. Only the user ID and role. \n
Implementing JWT with jsonwebtoken
\n\nuse jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};\nuse serde::{Serialize, Deserialize};\nuse chrono::{Utc, Duration};\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct Claims {\n pub sub: String, // User ID\n pub exp: usize, // expiration timestamp\n pub iat: usize, // issued at\n}\n\npub fn create_token(user_id: &str, secret: &str) -> Result<String, jsonwebtoken::errors::Error> {\n let now = Utc::now();\n let claims = Claims {\n sub: user_id.to_owned(),\n exp: (now + Duration::minutes(30)).timestamp() as usize,\n iat: now.timestamp() as usize,\n };\n encode(&Header::default(), &claims, &EncodingKey::from_secret(secret.as_bytes()))\n}\n\npub fn validate_token(token: &str, secret: &str) -> Result<Claims, jsonwebtoken::errors::Error> {\n let token_data = decode::<Claims>(\n token,\n &DecodingKey::from_secret(secret.as_bytes()),\n &Validation::default(),\n )?;\n Ok(token_data.claims)\n}\n\n3. Putting It All Together: Actix-web + Middleware
\n\nNow let's combine hashing and JWT into a full-fledged web application using Actix-web. We'll write middleware that checks the token on every protected request.
\n\nProject Structure
\nsrc/\n├── main.rs\n├── auth.rs # hashing, JWT\n├── middleware.rs # token verification\n└── handlers.rs #