Spaces:
Sleeping
Sleeping
| """Better Auth session token verification.""" | |
| import asyncio | |
| from typing import Optional, Dict, Any | |
| from datetime import datetime, timezone | |
| from sqlalchemy.ext.asyncio import AsyncSession | |
| from sqlalchemy import text | |
| class SessionError(Exception): | |
| """Session validation error.""" | |
| pass | |
| async def verify_session_token(token: str, db: AsyncSession) -> Optional[str]: | |
| """ | |
| Verify Better Auth session token against database. | |
| Args: | |
| token: Session token from Better Auth | |
| db: Database session | |
| Returns: | |
| User ID if session is valid, None otherwise | |
| Raises: | |
| SessionError: If session is invalid or expired | |
| """ | |
| import logging | |
| logger = logging.getLogger(__name__) | |
| try: | |
| # Query session table for this token | |
| query = text(""" | |
| SELECT "userId", "expiresAt" | |
| FROM session | |
| WHERE token = :token | |
| """) | |
| result = await db.execute(query, {"token": token}) | |
| row = result.fetchone() | |
| if not row: | |
| logger.warning(f"Session not found for token: {token[:20]}...") | |
| raise SessionError("Session not found") | |
| user_id, expires_at = row | |
| logger.debug(f"Found session for user: {user_id}, expires: {expires_at}") | |
| # Check if session has expired | |
| # Handle both timezone-aware and naive datetimes | |
| now = datetime.now(timezone.utc) | |
| # If expires_at is naive, make it timezone-aware (assume UTC) | |
| if expires_at.tzinfo is None: | |
| expires_at = expires_at.replace(tzinfo=timezone.utc) | |
| if expires_at < now: | |
| logger.warning(f"Session expired: {expires_at} < {now}") | |
| raise SessionError("Session expired") | |
| logger.info(f"Session validated successfully for user: {user_id}") | |
| return user_id | |
| except Exception as e: | |
| if isinstance(e, SessionError): | |
| raise | |
| logger.error(f"Session validation error: {str(e)}") | |
| raise SessionError(f"Session validation failed: {str(e)}") | |