From 21f3a713f6484b05905e801a1f81915da94fc5ef Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Wed, 28 Jan 2026 18:45:02 +0000 Subject: [PATCH] Fix a bug with validate returning 401 when a session was refreshed. Simplify & cleanup. --- paskia/authsession.py | 15 ----------- paskia/fastapi/api.py | 63 +++++++++++++++++++------------------------ 2 files changed, 27 insertions(+), 51 deletions(-) diff --git a/paskia/authsession.py b/paskia/authsession.py index ea9df82..9eb3f11 100644 --- a/paskia/authsession.py +++ b/paskia/authsession.py @@ -39,21 +39,6 @@ def get_reset(token: str) -> "ResetToken": raise ValueError("This authentication link is no longer valid.") -def refresh_session_token(token: str, *, ip: str, user_agent: str): - """Refresh a session extending its expiry.""" - session_record = db.data().sessions.get(token) - if not session_record: - raise ValueError("Session not found or expired") - updated = db.update_session( - token, - ip=ip, - user_agent=user_agent, - expiry=expires(), - ) - if not updated: - raise ValueError("Session not found or expired") - - def delete_credential(credential_uuid: UUID, auth: str, host: str | None = None): """Delete a specific credential for the current user.""" ctx = db.data().session_ctx(auth, hostutil.normalize_host(host)) diff --git a/paskia/fastapi/api.py b/paskia/fastapi/api.py index 9dd1e7b..1505785 100644 --- a/paskia/fastapi/api.py +++ b/paskia/fastapi/api.py @@ -14,11 +14,7 @@ from fastapi.responses import JSONResponse from fastapi.security import HTTPBearer from paskia import db -from paskia.authsession import ( - EXPIRES, - get_reset, - refresh_session_token, -) +from paskia.authsession import EXPIRES, expires, get_reset from paskia.fastapi import authz, session, user from paskia.fastapi.response import MsgspecResponse from paskia.fastapi.session import AUTH_COOKIE, AUTH_COOKIE_NAME @@ -93,19 +89,14 @@ async def validate_token( if auth: consumed = EXPIRES - (ctx.session.expiry - datetime.now(UTC)) if not timedelta(0) < consumed < _REFRESH_INTERVAL: - try: - refresh_session_token( - auth, - ip=request.client.host if request.client else "", - user_agent=request.headers.get("user-agent") or "", - ) - session.set_session_cookie(response, auth) - renewed = True - except ValueError: - # Session disappeared, e.g. due to concurrent logout; global handler will clear - raise authz.AuthException( - status_code=401, detail="Session expired", mode="login" - ) + db.update_session( + auth, + ip=request.client.host if request.client else "", + user_agent=request.headers.get("user-agent") or "", + expiry=expires(), + ) + session.set_session_cookie(response, auth) + renewed = True return MsgspecResponse( { "valid": True, @@ -115,24 +106,6 @@ async def validate_token( ) -@app.get("/token-info") -async def token_info(credentials=Depends(bearer_auth)): - """Get reset/device-add token info. Pass token via Bearer header.""" - token = credentials.credentials - if not passphrase.is_well_formed(token): - raise HTTPException(400, "Invalid token format") - try: - reset_token = get_reset(token) - except ValueError as e: - raise HTTPException(401, str(e)) - - u = reset_token.user - return { - "token_type": reset_token.token_type, - "display_name": u.display_name, - } - - @app.get("/forward") async def forward_authentication( request: Request, @@ -248,6 +221,24 @@ async def api_user_info( ) +@app.get("/token-info") +async def token_info(credentials=Depends(bearer_auth)): + """Get reset/device-add token info. Pass token via Bearer header.""" + token = credentials.credentials + if not passphrase.is_well_formed(token): + raise HTTPException(400, "Invalid token format") + try: + reset_token = get_reset(token) + except ValueError as e: + raise HTTPException(401, str(e)) + + u = reset_token.user + return { + "token_type": reset_token.token_type, + "display_name": u.display_name, + } + + @app.post("/logout") async def api_logout(request: Request, response: Response, auth=AUTH_COOKIE): if not auth: