odysseus-dev/odysseus · error · HTTPException
Not authenticated
Error message
Not authenticated
What it means
Raised as HTTP 401 by POST /change-password when _get_current_user(request) returns falsy, i.e. the request carries no valid session cookie. _get_current_user resolves the SESSION_COOKIE against the auth manager's session store; missing, expired, revoked, or unknown tokens all yield None. Password-change is a privileged operation, so an unauthenticated request is rejected before any validation.
Source
Thrown at routes/auth_routes.py:204
# set merged with DEFAULT_PRIVILEGES.
try:
u = result.get("username")
if u:
result["privileges"] = auth_manager.get_privileges(u)
except Exception:
pass
return result
@router.get("/policy")
async def auth_policy():
"""Return public auth policy constants for the frontend."""
return auth_manager.policy()
@router.post("/change-password")
async def change_password(body: ChangePasswordRequest, request: Request):
user = _get_current_user(request)
if not user:
raise HTTPException(401, "Not authenticated")
if len(body.new_password) < PASSWORD_MIN_LENGTH:
raise HTTPException(400, f"Password must be at least {PASSWORD_MIN_LENGTH} characters")
current_token = request.cookies.get(SESSION_COOKIE)
ok = await asyncio.to_thread(auth_manager.change_password, user, body.current_password, body.new_password)
if not ok:
raise HTTPException(400, "Current password is incorrect")
await asyncio.to_thread(auth_manager.revoke_user_sessions, user, current_token)
return {"ok": True}
# ------------------------------------------------------------------
# Two-factor authentication
# ------------------------------------------------------------------
@router.post("/2fa/setup")
async def totp_setup(request: Request):
"""Generate a TOTP secret and return the QR code URI."""
user = _get_current_user(request)
if not user:View on GitHub (pinned to f9235ebbf1)
Solutions
- Log in again to obtain a fresh session cookie, then retry the password change.
- Ensure the client sends cookies: fetch(url, {credentials: 'include'}) or keeps the cookie jar in curl/tests.
- If sessions were revoked (e.g. password changed on another device), re-authenticate on each device.
- Have the frontend detect 401 on this route and redirect to the login page with a return URL.
Example fix
// before
await fetch('/change-password', {method:'POST', body: JSON.stringify(payload)});
// after — include the session cookie and handle expiry
const res = await fetch('/change-password', {method:'POST', credentials:'include', headers:{'Content-Type':'application/json'}, body: JSON.stringify(payload)});
if (res.status === 401) { location.href = '/login?next=/settings'; } Defensive patterns
Strategy: validation
Validate before calling
// Confirm the session is alive before showing the change-password form
const s = await fetch('/2fa/status', {credentials:'include'});
if (s.status === 401) { location.href = '/login?next=/settings'; return; } Try / catch
catch (e) { if (e.status === 401) { saveDraft(); location.href = '/login?next=/settings'; } } Prevention
- Always send credentials: 'include' on authenticated endpoints.
- Probe session validity on page load instead of waiting for the form submit to fail.
- Preserve form state across the re-login redirect.
When it happens
Trigger: Calling /change-password with no session cookie, with a session that expired (past TOKEN_TTL or browser session end), with a token revoked by another password change or logout-all, or with a cookie not sent because the request is cross-site and SameSite=lax blocks it.
Common situations: Session expired while the settings page sat open, cookie lost after password change elsewhere (sessions revoked), testing API endpoints with curl while forgetting the cookie jar, or a frontend fetch missing credentials: 'include'.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Invalid credentials
- HTTP ' + r.status
- Assistant session could not be resolved
- Username already taken
- Current password is incorrect
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/bde97a18a2a890a9.
Report an issue: GitHub.