Refactor to not use status: success, but HTTP codes, and renamed the error key to detail to match FastAPI's own.

This commit is contained in:
Leo Vasanko 2025-08-06 10:09:55 -06:00
parent cf138d90c5
commit 9f423135ed
6 changed files with 37 additions and 39 deletions

View File

@ -48,7 +48,7 @@ onMounted(async () => {
try {
const response = await fetch('/auth/create-link', { method: 'POST' })
const result = await response.json()
if (result.error) throw new Error(result.error)
if (result.detail) throw new Error(result.detail)
url.value = result.url

View File

@ -36,8 +36,8 @@ export const useAuthStore = defineStore('auth', {
headers: {'Authorization': `Bearer ${sessionToken}`},
})
const result = await response.json()
if (result.error) {
throw new Error(result.error)
if (result.detail) {
throw new Error(result.detail)
}
return result
},
@ -73,7 +73,7 @@ export const useAuthStore = defineStore('auth', {
async loadUserInfo() {
const response = await fetch('/auth/user-info', {method: 'POST'})
const result = await response.json()
if (result.error) throw new Error(`Server: ${result.error}`)
if (result.detail) throw new Error(`Server: ${result.detail}`)
this.currentUser = result.user
this.currentCredentials = result.credentials || []
@ -82,9 +82,9 @@ export const useAuthStore = defineStore('auth', {
console.log('User info loaded:', result)
},
async deleteCredential(uuid) {
const response = await fetch(`/auth/credential/${uuid}`, {method: 'DELETE'})
const response = await fetch(`/auth/credential/${uuid}`, {method: 'Delete'})
const result = await response.json()
if (result.error) throw new Error(`Server: ${result.error}`)
if (result.detail) throw new Error(`Server: ${result.detail}`)
await this.loadUserInfo()
},

View File

@ -57,8 +57,8 @@ class AwaitableWebSocket extends WebSocket {
console.error("Failed to parse JSON from WebSocket message", data, err)
throw new Error("Failed to parse JSON from WebSocket message")
}
if (parsed.error) {
throw new Error(`Server: ${parsed.error}`)
if (parsed.detail) {
throw new Error(`Server: ${parsed.detail}`)
}
return parsed
}

View File

@ -28,17 +28,17 @@ def register_api_routes(app: FastAPI):
"""Register all API routes on the FastAPI app."""
@app.post("/auth/validate")
async def validate_token(auth=Cookie(None)):
async def validate_token(response: Response, auth=Cookie(None)):
"""Lightweight token validation endpoint."""
try:
s = await get_session(auth)
return {
"status": "success",
"valid": True,
"user_uuid": str(s.user_uuid),
}
except ValueError:
return {"status": "error", "valid": False}
response.status_code = 401
return {"valid": False}
@app.post("/auth/user-info")
async def api_user_info(response: Response, auth=Cookie(None)):
@ -84,7 +84,6 @@ def register_api_routes(app: FastAPI):
credentials.sort(key=lambda cred: cred["created_at"])
return {
"status": "success",
"authenticated": not reset,
"session_type": s.info["type"],
"user": {
@ -99,24 +98,23 @@ def register_api_routes(app: FastAPI):
}
except ValueError as e:
response.status_code = 400
return {"error": f"Failed to get user info: {e}"}
return {"detail": f"Failed to get user info: {e}"}
except Exception:
response.status_code = 500
return {"error": "Failed to get user info"}
return {"detail": "Failed to get user info"}
@app.post("/auth/logout")
async def api_logout(response: Response, auth=Cookie(None)):
"""Log out the current user by clearing the session cookie and deleting from database."""
if not auth:
return {"status": "success", "message": "Already logged out"}
return {"message": "Already logged out"}
# Remove from database if possible
try:
await db.instance.delete_session(session_key(auth))
except Exception:
...
response.delete_cookie("auth")
return {"status": "success", "message": "Logged out successfully"}
return {"message": "Logged out successfully"}
@app.post("/auth/set-session")
async def api_set_session(response: Response, auth=Depends(bearer_auth)):
@ -128,17 +126,16 @@ def register_api_routes(app: FastAPI):
session.set_session_cookie(response, auth.credentials)
return {
"status": "success",
"message": "Session cookie set successfully",
"user_uuid": str(user.user_uuid),
}
except ValueError as e:
response.status_code = 400
return {"error": str(e)}
return {"detail": str(e)}
except Exception:
response.status_code = 500
return {"error": "Failed to set session"}
return {"detail": "Failed to set session"}
@app.delete("/auth/credential/{uuid}")
async def api_delete_credential(
@ -147,11 +144,11 @@ def register_api_routes(app: FastAPI):
"""Delete a specific credential for the current user."""
try:
await delete_credential(uuid, auth)
return {"status": "success", "message": "Credential deleted successfully"}
return {"message": "Credential deleted successfully"}
except ValueError as e:
response.status_code = 400
return {"error": str(e)}
return {"detail": str(e)}
except Exception:
response.status_code = 500
return {"error": "Failed to delete credential"}
return {"detail": "Failed to delete credential"}

View File

@ -1,6 +1,6 @@
import logging
from fastapi import Cookie, HTTPException, Request
from fastapi import Cookie, HTTPException, Request, Response
from fastapi.responses import RedirectResponse
from ..authsession import expires, get_session
@ -13,7 +13,7 @@ def register_reset_routes(app):
"""Register all device addition/reset routes on the FastAPI app."""
@app.post("/auth/create-link")
async def api_create_link(request: Request, auth=Cookie(None)):
async def api_create_link(request: Request, response: Response, auth=Cookie(None)):
"""Create a device addition link for the authenticated user."""
try:
# Require authentication
@ -33,16 +33,17 @@ def register_reset_routes(app):
url = f"{request.headers['origin']}{path}"
return {
"status": "success",
"message": "Registration link generated successfully",
"url": url,
"expires": expires().isoformat(),
}
except ValueError:
return {"error": "Authentication required"}
response.status_code = 401
return {"detail": "Authentication required"}
except Exception as e:
return {"error": f"Failed to create registration link: {str(e)}"}
response.status_code = 500
return {"detail": f"Failed to create registration link: {str(e)}"}
@app.get("/auth/{reset_token}")
async def reset_authentication(

View File

@ -16,9 +16,10 @@ import uuid7
from fastapi import Cookie, FastAPI, Query, WebSocket, WebSocketDisconnect
from webauthn.helpers.exceptions import InvalidAuthenticationResponse
from ..authsession import EXPIRES, create_session, get_session
from ..authsession import EXPIRES, create_session, get_reset, get_session
from ..db import User, db
from ..sansio import Passkey
from ..util import passphrase
from ..util.tokens import create_token, session_key
from .session import infodict
@ -80,18 +81,17 @@ async def websocket_register_new(
await ws.send_json(
{
"status": "success",
"user_uuid": str(user_uuid),
"session_token": token,
}
)
except ValueError as e:
await ws.send_json({"error": str(e)})
await ws.send_json({"detail": str(e)})
except WebSocketDisconnect:
pass
except Exception:
logging.exception("Internal Server Error")
await ws.send_json({"error": "Internal Server Error"})
await ws.send_json({"detail": "Internal Server Error"})
@app.websocket("/add_credential")
@ -100,7 +100,9 @@ async def websocket_register_add(ws: WebSocket, auth=Cookie(None)):
await ws.accept()
origin = ws.headers["origin"]
try:
s = await get_session(auth, reset_allowed=True)
# Try to get either a regular session or a reset session
reset = passphrase.is_well_formed(auth)
s = await (get_reset if reset else get_session)(auth)
user_uuid = s.user_uuid
# Get user information to get the user_name
@ -126,7 +128,6 @@ async def websocket_register_add(ws: WebSocket, auth=Cookie(None)):
await ws.send_json(
{
"status": "success",
"user_uuid": str(user.uuid),
"credential_uuid": str(credential.uuid),
"session_token": token,
@ -134,12 +135,12 @@ async def websocket_register_add(ws: WebSocket, auth=Cookie(None)):
}
)
except ValueError as e:
await ws.send_json({"error": str(e)})
await ws.send_json({"detail": str(e)})
except WebSocketDisconnect:
pass
except Exception:
logging.exception("Internal Server Error")
await ws.send_json({"error": "Internal Server Error"})
await ws.send_json({"detail": "Internal Server Error"})
@app.websocket("/authenticate")
@ -168,16 +169,15 @@ async def websocket_authenticate(ws: WebSocket):
await ws.send_json(
{
"status": "success",
"user_uuid": str(stored_cred.user_uuid),
"session_token": token,
}
)
except (ValueError, InvalidAuthenticationResponse) as e:
logging.exception("ValueError")
await ws.send_json({"error": str(e)})
await ws.send_json({"detail": str(e)})
except WebSocketDisconnect:
pass
except Exception:
logging.exception("Internal Server Error")
await ws.send_json({"error": "Internal Server Error"})
await ws.send_json({"detail": "Internal Server Error"})