fix(api): perbaiki keamanan auth & WebSocket, tambah rate limiting

Security fixes hasil audit:
- fix(auth): refresh token kini memakai claim typ=refresh; access token
  tidak bisa dipakai sebagai refresh token (sebelumnya bisa — eskalasi
  masa berlaku 1 jam -> 7 hari)
- fix(api): layer JWT hanya melindungi route /sessions dan /chat;
  /auth/login, /auth/register, /auth/refresh, /health kini publik
  (sebelumnya semua route 401-lock, API tidak bisa dipakai sama sekali)
- fix(ws): endpoint /ws kini memverifikasi token ZESDEX_WS_TOKEN via
  query param jika env diset (mencegah pemakaian LLM proxy terbuka)
- feat(api): rate limiting login/register/refresh (20 request / 10 menit
  per client IP) memakai RateLimiter yang tadinya dead code
- test(jwt): tambah unit test token type access vs refresh + expired
This commit is contained in:
asepharyana
2026-08-27 22:04:32 +07:00
parent 7f64423615
commit 6db00b2266
7 changed files with 219 additions and 25 deletions
@@ -98,6 +98,21 @@ where
if let Some(token) = auth_value.strip_prefix("Bearer ") {
match zesdex_infrastructure::auth::jwt::verify_token(&secret, token) {
Ok(claims) => {
// Reject refresh tokens on protected routes — only access
// tokens are acceptable here.
if claims.token_type
!= zesdex_infrastructure::auth::jwt::TokenType::Access
{
let response = (
StatusCode::UNAUTHORIZED,
Json(json!({
"error": "Invalid token",
"detail": "refresh tokens are not accepted on protected routes"
})),
)
.into_response();
return Box::pin(async move { Ok(response) });
}
// Inject claims as extension for downstream handlers
let mut req = req;
req.extensions_mut().insert(JwtClaims {