Skip to content

Commit 8224363

Browse files
committed
Refactor authentication: Remove Remember Me API endpoints and schemas; implement cookie-based Remember Me functionality
1 parent eb399ec commit 8224363

4 files changed

Lines changed: 414 additions & 614 deletions

File tree

server/api_server/api_server_start.py

Lines changed: 1 addition & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1936,144 +1936,7 @@ def check_auth(payload=None):
19361936
return jsonify({"success": True, "message": "Authentication check successful"}), 200
19371937

19381938

1939-
# --------------------------
1940-
# Remember Me Validation endpoint
1941-
# --------------------------
1942-
@app.route("/auth/validate-remember", methods=["POST"])
1943-
@validate_request(
1944-
operation_id="validate_remember",
1945-
summary="Validate Remember Me Token",
1946-
description="Validate a persistent Remember Me token against stored hash. Called from login page (no auth required).",
1947-
request_model=ValidateRememberRequest,
1948-
response_model=ValidateRememberResponse,
1949-
tags=["auth"],
1950-
auth_callable=None # No auth required - used on login page
1951-
)
1952-
def validate_remember(payload=None):
1953-
"""
1954-
Validate a Remember Me token from persistent cookie.
1955-
1956-
Security: Uses timing-safe hash comparison to prevent timing attacks.
1957-
Token format: hex-encoded 32 random bytes (64 chars) from bin2hex(random_bytes(32))
1958-
"""
1959-
try:
1960-
# Extract token from request
1961-
data = request.get_json() or {}
1962-
token = data.get("token")
1963-
1964-
if not token:
1965-
mylog("verbose", ["[auth/validate-remember] Missing token in request"])
1966-
return jsonify({
1967-
"success": True,
1968-
"valid": False,
1969-
"message": "Token validation failed: missing token"
1970-
}), 200
1971-
1972-
# Validate token against stored hash
1973-
params_instance = ParametersInstance()
1974-
result = params_instance.validate_token(token)
1975-
1976-
if result['valid']:
1977-
mylog("verbose", ["[auth/validate-remember] Token validation successful"])
1978-
return jsonify({
1979-
"success": True,
1980-
"valid": True,
1981-
"message": "Token validation successful"
1982-
}), 200
1983-
else:
1984-
mylog("verbose", ["[auth/validate-remember] Token validation failed"])
1985-
return jsonify({
1986-
"success": True,
1987-
"valid": False,
1988-
"message": "Token validation failed"
1989-
}), 200
1990-
1991-
except Exception as e:
1992-
mylog("verbose", [f"[auth/validate-remember] Unexpected error: {e}"])
1993-
return jsonify({
1994-
"success": False,
1995-
"valid": False,
1996-
"error": "Internal server error",
1997-
"message": "An unexpected error occurred during token validation"
1998-
}), 500
1999-
2000-
2001-
# --------------------------
2002-
# Remember Me Save endpoint
2003-
# --------------------------
2004-
@app.route("/auth/remember-me/save", methods=["POST"])
2005-
@validate_request(
2006-
operation_id="save_remember",
2007-
summary="Save Remember Me Token",
2008-
description="Save a Remember Me token to the database. Called after successful login to enable persistent authentication.",
2009-
request_model=SaveRememberRequest,
2010-
response_model=SaveRememberResponse,
2011-
tags=["auth"],
2012-
auth_callable=None # No auth required - used on login page
2013-
)
2014-
def save_remember(payload=None):
2015-
"""
2016-
Save a Remember Me token.
2017-
2018-
Flow:
2019-
1. User logs in with "Remember Me" checkbox
2020-
2. Password validated successfully
2021-
3. Token generated: bin2hex(random_bytes(32))
2022-
4. This endpoint called: saves hash(token) to Parameters table
2023-
5. Token (unhashed) set in persistent cookie
2024-
6. Session created and user redirected
2025-
2026-
Security: Only the HASH is stored in the database, not the token itself.
2027-
If database is compromised, attacker cannot use stolen hashes without the original token.
2028-
"""
2029-
try:
2030-
import uuid
2031-
import hashlib
2032-
2033-
# Extract token from request
2034-
data = request.get_json() or {}
2035-
token = data.get("token")
2036-
2037-
if not token or len(token) < 64:
2038-
mylog("verbose", ["[auth/remember-me/save] Invalid or missing token"])
2039-
return jsonify({
2040-
"success": False,
2041-
"error": "Invalid token",
2042-
"message": "Token must be 64+ hex characters"
2043-
}), 400
2044-
2045-
# Hash the token
2046-
token_hash = hashlib.sha256(token.encode('utf-8')).hexdigest()
2047-
2048-
# Generate UUID-based parameter ID
2049-
token_id = f"remember_me_token_{uuid.uuid4()}"
2050-
2051-
# Store hash in Parameters table
2052-
params_instance = ParametersInstance()
2053-
success = params_instance.set_parameter(token_id, token_hash)
2054-
2055-
if success:
2056-
mylog("verbose", [f"[auth/remember-me/save] Token saved successfully: {token_id}"])
2057-
return jsonify({
2058-
"success": True,
2059-
"message": "Remember Me token saved successfully",
2060-
"token_id": token_id
2061-
}), 200
2062-
else:
2063-
mylog("verbose", ["[auth/remember-me/save] Failed to save token to database"])
2064-
return jsonify({
2065-
"success": False,
2066-
"error": "Database error",
2067-
"message": "Failed to save Remember Me token"
2068-
}), 500
2069-
2070-
except Exception as e:
2071-
mylog("verbose", [f"[auth/remember-me/save] Unexpected error: {e}"])
2072-
return jsonify({
2073-
"success": False,
2074-
"error": "Internal server error",
2075-
"message": "An unexpected error occurred while saving Remember Me token"
2076-
}), 500
1939+
# Remember Me is now implemented via cookies only (no API endpoints required)
20771940

20781941

20791942
# --------------------------

server/api_server/openapi/schemas.py

Lines changed: 1 addition & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,82 +1036,7 @@ class GetSettingResponse(BaseResponse):
10361036
# =============================================================================
10371037

10381038

1039-
class ValidateRememberRequest(BaseModel):
1040-
"""Request to validate a Remember Me token."""
1041-
model_config = ConfigDict(
1042-
json_schema_extra={
1043-
"examples": [{
1044-
"token": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2"
1045-
}]
1046-
}
1047-
)
1048-
1049-
token: str = Field(
1050-
...,
1051-
min_length=64,
1052-
max_length=128,
1053-
description="The unhashed Remember Me token from persistent cookie (hex-encoded binary)"
1054-
)
1055-
1056-
1057-
class ValidateRememberResponse(BaseResponse):
1058-
"""Response from Remember Me token validation."""
1059-
model_config = ConfigDict(
1060-
extra="allow",
1061-
json_schema_extra={
1062-
"examples": [{
1063-
"success": True,
1064-
"valid": True,
1065-
"message": "Token validation successful"
1066-
}, {
1067-
"success": True,
1068-
"valid": False,
1069-
"message": "Token validation failed"
1070-
}]
1071-
}
1072-
)
1073-
1074-
valid: bool = Field(
1075-
...,
1076-
description="Whether the token is valid and matches stored hash"
1077-
)
1078-
1079-
1080-
class SaveRememberRequest(BaseModel):
1081-
"""Request to save a Remember Me token."""
1082-
model_config = ConfigDict(
1083-
json_schema_extra={
1084-
"examples": [{
1085-
"token": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2"
1086-
}]
1087-
}
1088-
)
1089-
1090-
token: str = Field(
1091-
...,
1092-
min_length=64,
1093-
max_length=128,
1094-
description="The unhashed Remember Me token to save (hex-encoded binary from bin2hex(random_bytes(32)))"
1095-
)
1096-
1097-
1098-
class SaveRememberResponse(BaseResponse):
1099-
"""Response from Remember Me token save operation."""
1100-
model_config = ConfigDict(
1101-
extra="allow",
1102-
json_schema_extra={
1103-
"examples": [{
1104-
"success": True,
1105-
"message": "Token saved successfully",
1106-
"token_id": "remember_me_token_550e8400-e29b-41d4-a716-446655440000"
1107-
}]
1108-
}
1109-
)
1110-
1111-
token_id: Optional[str] = Field(
1112-
None,
1113-
description="The parameter ID where token hash was stored (UUID-based)"
1114-
)
1039+
# Remember Me schemas removed - Remember Me now uses cookies only (no API endpoints)
11151040

11161041

11171042
# =============================================================================

0 commit comments

Comments
 (0)