feat: implement httpOnly cookie for JWT authentication and update related API calls

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-04-28 14:36:06 -04:00
parent 2eb887c486
commit 567fa66428
27 changed files with 207 additions and 123 deletions
+15 -1
View File
@@ -3,6 +3,20 @@ use jsonwebtoken::{EncodingKey, Header, encode};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
/// Genera el valor del header `Set-Cookie` para el token JWT como httpOnly cookie.
/// Usa SameSite=Strict y Secure para producción.
pub fn auth_cookie_header(token: &str) -> String {
format!(
"auth_token={}; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600",
token
)
}
/// Genera el valor del header `Set-Cookie` para eliminar la cookie de auth.
pub fn auth_cookie_clear_header() -> &'static str {
"auth_token=; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=0"
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Claims {
pub sub: Uuid,
@@ -19,7 +33,7 @@ pub fn create_jwt(
role: &str,
) -> Result<String, jsonwebtoken::errors::Error> {
let expiration = Utc::now()
.checked_add_signed(Duration::hours(24))
.checked_add_signed(Duration::hours(1))
.expect("valid timestamp")
.timestamp();
+26 -9
View File
@@ -28,17 +28,34 @@ pub async fn org_extractor_middleware(
let token = if let Some(token_str) = auth_header.and_then(|s: &str| s.strip_prefix("Bearer ")) {
token_str.to_string()
} else {
// Verificar si hay preview_token en la cadena de consulta
let query = req.uri().query().unwrap_or_default();
let preview_token = query
.split('&')
.find(|part| part.starts_with("preview_token="))
.and_then(|part| part.split('=').nth(1));
// Intentar leer el token desde la httpOnly cookie
let cookie_token = req
.headers()
.get("cookie")
.and_then(|v| v.to_str().ok())
.and_then(|cookie_str| {
cookie_str.split(';').find_map(|part| {
let part = part.trim();
part.strip_prefix("auth_token=")
})
})
.map(|t| t.to_string());
if let Some(token) = preview_token {
token.to_string()
if let Some(token) = cookie_token {
token
} else {
return Err(StatusCode::UNAUTHORIZED);
// Verificar si hay preview_token en la cadena de consulta
let query = req.uri().query().unwrap_or_default();
let preview_token = query
.split('&')
.find(|part| part.starts_with("preview_token="))
.and_then(|part| part.split('=').nth(1));
if let Some(token) = preview_token {
token.to_string()
} else {
return Err(StatusCode::UNAUTHORIZED);
}
}
};