"""자체 세션 토큰 구글 검증을 통과한 뒤로는 이걸 HttpOnly 쿠키로 들고 다닌다 담는 것은 user.id 하나다. 이메일·이름은 바뀔 수 있어 토큰에 넣지 않고 매번 DB에서 읽는다. """ from datetime import datetime, timedelta, timezone from jose import JWTError, jwt from settings import settings ALGORITHM = "HS256" COOKIE_NAME = "poster_alive_session" class SessionInvalid(RuntimeError): """서명이 안 맞거나 만료됨""" def issue(user_id: str) -> str: if not settings.jwt_secret: raise RuntimeError("JWT_SECRET 없음 — 세션을 발급할 수 없습니다") expires = datetime.now(timezone.utc) + timedelta(days=settings.jwt_days) return jwt.encode({"sub": user_id, "exp": expires}, settings.jwt_secret, algorithm=ALGORITHM) def read(token: str) -> str: """토큰에서 user.id를 꺼낸다""" try: claims = jwt.decode(token, settings.jwt_secret, algorithms=[ALGORITHM]) except JWTError as failure: raise SessionInvalid("세션이 유효하지 않습니다") from failure user_id = str(claims.get("sub") or "") if not user_id: raise SessionInvalid("sub 없음") return user_id def cookie_max_age() -> int: return settings.jwt_days * 24 * 3600