""" Authentication service with OIDC and social media support """ from datetime import datetime, timedelta from typing import Optional from jose import jwt from fastapi import HTTPException, status from sqlalchemy.orm import Session from ..config.settings import settings from ..models import User from ..database import SessionLocal def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): """Create a JWT access token""" to_encode = data.copy() if expires_delta: expire = datetime.utcnow() + expires_delta else: expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) to_encode.update({"exp": expire}) encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM) return encoded_jwt def verify_token(token: str) -> dict: """Verify a JWT token and return the payload""" try: payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]) return payload except jwt.JWTError: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) def authenticate_user(db: Session, username: str, password: str) -> Optional[User]: """Authenticate a user with username and password""" user = db.query(User).filter(User.username == username).first() if not user or not verify_password_correct(password, user.hashed_password): return None if not user.is_active: return None return user async def get_oidc_config(): """Get OIDC configuration""" return { "issuer": settings.OIDC_ISSUER, "authorization_endpoint": f"{settings.OIDC_ISSUER}/authorize" if settings.OIDC_ISSUER else None, "token_endpoint": f"{settings.OIDC_ISSUER}/token" if settings.OIDC_ISSUER else None, "userinfo_endpoint": f"{settings.OIDC_ISSUER}/userinfo" if settings.OIDC_ISSUER else None, "jwks_uri": f"{settings.OIDC_ISSUER}/.well-known/jwks.json" if settings.OIDC_ISSUER else None, "client_id": settings.OIDC_CLIENT_ID, "redirect_uri": settings.OIDC_REDIRECT_URI, } async def handle_oidc_callback(code: str) -> User: """ Handle OIDC callback and return or create a user This is a simplified implementation - in a real app you'd exchange the code for tokens and fetch user info from the OIDC provider """ # In a real implementation, you would: # 1. Exchange the authorization code for access/id tokens # 2. Validate the ID token # 3. Fetch user info from the userinfo endpoint # 4. Create or update the user in your database # 5. Return the user object # For now, return a placeholder - this would be replaced with real OIDC logic raise NotImplementedError("OIDC callback handling not fully implemented") async def handle_social_login(provider: str, access_token: str) -> User: """ Handle social media login (Google, Facebook, etc.) This is a simplified implementation """ # In a real implementation, you would: # 1. Validate the access token with the social provider # 2. Fetch user info from the provider's API # 3. Create or update the user in your database # 4. Return the user object # For now, return a placeholder - this would be replaced with real social login logic raise NotImplementedError("Social login handling not fully implemented") def hash_password(password: str) -> str: """ Hash a password using bcrypt """ from ..utils.security import get_password_hash return get_password_hash(password) def verify_password_correct(plain_password: str, hashed_password: str) -> bool: """ Verify a plain password against its hash """ from ..utils.security import verify_password as verify_password_util return verify_password_util(plain_password, hashed_password)