Files
comfy-discord-web/web/routers/auth_router.py
Khoa (Revenovich) Tran Gia 1ed3c9ec4b Initial commit — ComfyUI Discord bot + web UI
Full source for the-third-rev: Discord bot (discord.py), FastAPI web UI
(React/TS/Vite/Tailwind), ComfyUI integration, generation history DB,
preset manager, workflow inspector, and all supporting modules.

Excluded from tracking: .env, invite_tokens.json, *.db (SQLite),
current-workflow-changes.json, user_settings/, presets/, logs/,
web-static/ (build output), frontend/node_modules/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 09:55:48 +07:00

65 lines
1.9 KiB
Python

"""POST /api/auth/login|logout; GET /api/auth/me"""
from __future__ import annotations
import logging
from fastapi import APIRouter, Depends, HTTPException, Request, Response, status
from pydantic import BaseModel
from web.auth import create_jwt, require_auth
from web.deps import get_config
from web.login_guard import get_guard, get_real_ip
router = APIRouter()
_COOKIE = "ttb_session"
audit = logging.getLogger("audit")
class LoginRequest(BaseModel):
token: str
@router.post("/login")
async def login(body: LoginRequest, request: Request, response: Response):
"""Exchange an invite token for a JWT session cookie."""
from token_store import verify_token
config = get_config()
token_file = config.web_token_file if config else "invite_tokens.json"
expire_hours = config.web_jwt_expire_hours if config else 8
ip = get_real_ip(request)
get_guard().check(ip)
record = verify_token(body.token, token_file)
if record is None:
get_guard().record_failure(ip)
audit.info("auth.login ip=%s success=False", ip)
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
label: str = record["label"]
admin: bool = record.get("admin", False)
get_guard().record_success(ip)
audit.info("auth.login ip=%s success=True label=%s", ip, label)
jwt_token = create_jwt(label, admin=admin, expire_hours=expire_hours)
response.set_cookie(
_COOKIE, jwt_token,
httponly=True, secure=True, samesite="strict",
max_age=expire_hours * 3600,
)
return {"label": label, "admin": admin}
@router.post("/logout")
async def logout(response: Response):
"""Clear the session cookie."""
response.delete_cookie(_COOKIE)
return {"ok": True}
@router.get("/me")
async def me(user: dict = Depends(require_auth)):
"""Return current user info."""
return {"label": user["sub"], "admin": user.get("admin", False)}