security: prevent re-use of refresh token (reduce surface for any stolen token)
Security: session hardening Refresh token rotation with theft detection (family_id) - Added family_id column to auth.sessions (migration 20260507000000_session_family.sql) grouping all tokens issued from the same login into a family - On refresh, the new session inherits the parent's family_id - If a revoked token is replayed (indicates the token was stolen after rotation), the entire family is immediately invalidated and a warning is logged — forcing re-authentication on all devices SameSite=Strict on refresh cookie - Access cookie stays SameSite=Lax (needed for top-level navigation) - Refresh cookie upgraded to SameSite=Strict — it is only ever used for explicit POST to /api/auth/refresh, never via cross-site navigation Refresh token TTL: 30 days → 7 days - With rotation, active sessions auto-renew and effectively never expire - Inactive sessions expire after 7 days instead of 30, reducing the theft window
This commit is contained in:
+11
@@ -468,6 +468,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
HeaderValue::from_static("camera=(), microphone=(), geolocation=()"),
|
||||
));
|
||||
|
||||
// Warn once at startup if auth cookies are not Secure.
|
||||
// HttpOnly + SameSite protection is nullified over plain HTTP because tokens
|
||||
// travel in cleartext and can be intercepted by a network observer.
|
||||
if !crate::interfaces::api::cookie_auth::is_cookie_secure() {
|
||||
tracing::warn!(
|
||||
"⚠️ SECURITY: auth cookies are NOT marked Secure. \
|
||||
Tokens will be transmitted in plaintext over HTTP. \
|
||||
Set OXICLOUD_COOKIE_SECURE=true for any HTTPS deployment."
|
||||
);
|
||||
}
|
||||
|
||||
// Start server — tuned socket for low-latency responses
|
||||
let addr = SocketAddr::from(([0, 0, 0, 0], config.server_port));
|
||||
tracing::info!("Starting OxiCloud server on http://{}", addr);
|
||||
|
||||
Reference in New Issue
Block a user