"""Auth client for integration tests.""" import logging logger = logging.getLogger(__name__) class AuthClient: """Wraps authentication-related API calls. Provides convenience methods for register, login, logout, and session management. Automatically stores the token on the parent SecuirdClient when login / register succeed. """ def __init__(self, client): self._client = client # ------------------------------------------------------------------ # Registration # ------------------------------------------------------------------ def register(self, email: str, password: str, full_name: str | None = None) -> dict: """Register a new user and return the response payload. Args: email: User's email address. password: Plain-text password (>= 8 chars). full_name: Optional display name. Returns: API response dict containing ``user``, ``token``, ``expires_at``. Raises: ApiError: On validation failure or duplicate email. """ logger.info(f"[AuthClient] Registering user: email={email}") payload = {"email": email, "password": password, "password_confirm": password} if full_name: payload["full_name"] = full_name result = self._client.post("/auth/register", data=payload) token = result.get("data", {}).get("token") if token: self._client.set_token(token) logger.info(f"[AuthClient] Registration successful — token stored") return result # ------------------------------------------------------------------ # Login / Logout # ------------------------------------------------------------------ def login(self, email: str, password: str, remember_me: bool = False) -> dict: """Authenticate with email and password. Args: email: Registered email address. password: Plain-text password. remember_me: Request a long-lived session. Returns: API response dict. If TOTP / WebAuthn is required the response contains ``requires_totp`` or ``requires_webauthn`` instead of a token. """ logger.info(f"[AuthClient] Logging in: email={email}") result = self._client.post( "/auth/login", data={"email": email, "password": password, "remember_me": remember_me}, ) token = result.get("data", {}).get("token") if token: self._client.set_token(token) logger.info(f"[AuthClient] Login successful — token stored") return result def logout(self) -> dict: """Log out the current user and clear the stored token.""" logger.info("[AuthClient] Logging out") result = self._client.post("/auth/logout") self._client.clear_token() return result # ------------------------------------------------------------------ # Current user # ------------------------------------------------------------------ def me(self) -> dict: """Return the current authenticated user's profile.""" return self._client.get("/auth/me") # ------------------------------------------------------------------ # Sessions # ------------------------------------------------------------------ def list_sessions(self) -> dict: """Return active sessions for the current user.""" return self._client.get("/auth/sessions") def revoke_session(self, session_id: str) -> dict: """Revoke a specific session belonging to the current user.""" return self._client.delete(f"/auth/sessions/{session_id}") # ------------------------------------------------------------------ # Password recovery # ------------------------------------------------------------------ def forgot_password(self, email: str) -> dict: """Request a password-reset email.""" return self._client.post("/auth/forgot-password", data={"email": email}) def reset_password(self, token: str, new_password: str, new_password_confirm: str) -> dict: """Reset password using a token from the forgot-password flow.""" return self._client.post( "/auth/reset-password", data={ "token": token, "password": new_password, "password_confirm": new_password_confirm, }, ) # ------------------------------------------------------------------ # Email verification # ------------------------------------------------------------------ def verify_email(self, token: str) -> dict: """Verify an email address using the token sent by email.""" return self._client.post("/auth/verify-email", data={"token": token}) def resend_verification(self, email: str) -> dict: """Re-send the verification email.""" return self._client.post("/auth/resend-verification", data={"email": email})