tmf656_slice/
auth.rs

1//! JWT Authentication for TMF656 API
2
3use actix_web::{Error as ActixError, HttpRequest};
4use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
5use serde::{Deserialize, Serialize};
6use std::env;
7
8/// JWT Claims
9#[derive(Serialize, Deserialize)]
10pub struct Claims {
11    pub sub: String,
12    pub exp: usize,
13}
14
15/// Generate a JWT token for a user
16pub fn generate_token(username: &str) -> String {
17    let secret = env::var("JWT_SECRET").unwrap_or_else(|_| "bssoss-secret".to_string());
18    let expiration = chrono::Utc::now()
19        .checked_add_signed(chrono::Duration::hours(8))
20        .expect("valid timestamp")
21        .timestamp() as usize;
22
23    let claims = Claims {
24        sub: username.to_owned(),
25        exp: expiration,
26    };
27
28    encode(
29        &Header::default(),
30        &claims,
31        &EncodingKey::from_secret(secret.as_ref()),
32    )
33    .expect("Token creation failed")
34}
35
36/// Validate a JWT token from the request
37pub fn validate_token(req: &HttpRequest) -> Result<String, ActixError> {
38    let secret = env::var("JWT_SECRET").unwrap_or_else(|_| "bssoss-secret".to_string());
39
40    if let Some(header_value) = req.headers().get("Authorization") {
41        let token = header_value
42            .to_str()
43            .map_err(|_| actix_web::error::ErrorBadRequest("Invalid authorization header"))?
44            .replace("Bearer ", "");
45
46        let token_data = decode::<Claims>(
47            &token,
48            &DecodingKey::from_secret(secret.as_ref()),
49            &Validation::default(),
50        )
51        .map_err(|_| actix_web::error::ErrorUnauthorized("Invalid or expired token"))?;
52
53        Ok(token_data.claims.sub)
54    } else {
55        Err(actix_web::error::ErrorUnauthorized(
56            "Missing authorization header",
57        ))
58    }
59}