Spaces:
Sleeping
Sleeping
| import os | |
| import jwt | |
| from fastapi import Depends, HTTPException | |
| from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials | |
| from sqlalchemy.orm import Session | |
| from dotenv import load_dotenv | |
| from app.db.database import get_db | |
| from app.db.models import User | |
| from app.services.coa_initializer import initialize_startup_coa | |
| load_dotenv() | |
| security = HTTPBearer() | |
| NEXTAUTH_SECRET = os.getenv("NEXTAUTH_SECRET") | |
| def get_current_user_claims( | |
| credentials: HTTPAuthorizationCredentials = Depends(security) | |
| ) -> dict: | |
| """ | |
| Accepts the NextAuth session token. | |
| NextAuth sends token.sub (the user UUID) as the Bearer token. | |
| We try to decode it as a JWT first; if it's just a plain UUID, we wrap it. | |
| """ | |
| token = credentials.credentials | |
| try: | |
| # Try to decode as a signed JWT (future-proof for when we pass full JWTs) | |
| decoded = jwt.decode( | |
| token, | |
| NEXTAUTH_SECRET, | |
| algorithms=["HS256"], | |
| options={"verify_aud": False} | |
| ) | |
| return decoded | |
| except Exception: | |
| # If it's not a JWT (it's a plain UUID), wrap it in a dict so the rest works | |
| if len(token) == 36 and token.count("-") == 4: # UUID format check | |
| return {"sub": token} | |
| raise HTTPException(status_code=401, detail="Invalid authentication token.") | |
| def get_current_user_id(decoded_token: dict = Depends(get_current_user_claims)) -> str: | |
| """Returns the user UUID from the verified JWT.""" | |
| return decoded_token.get("sub") | |
| def get_current_user( | |
| decoded_token: dict = Depends(get_current_user_claims), | |
| db: Session = Depends(get_db) | |
| ) -> User: | |
| """ | |
| Just-In-Time User Sync. | |
| Intercepts the token, checks if the user exists in PostgreSQL, | |
| and silently creates them (with their accounting buckets) if they don't! | |
| """ | |
| user_id = decoded_token.get("sub") | |
| email = decoded_token.get("email", "unknown@user.com") | |
| # 1. Check if user exists by UUID | |
| user = db.query(User).filter(User.user_id == user_id).first() | |
| if not user: | |
| # 2. Check if they exist by email (orphaned account) | |
| existing_email_user = db.query(User).filter(User.email == email).first() | |
| if existing_email_user: | |
| print(f"🔒 JIT AUTH: Relinking {email} to new ID...") | |
| existing_email_user.user_id = user_id | |
| db.commit() | |
| db.refresh(existing_email_user) | |
| return existing_email_user | |
| # 3. Brand new user — create them instantly! | |
| print(f"🔒 JIT AUTH: Registering new user {email}...") | |
| user = User( | |
| user_id=user_id, | |
| email=email, | |
| organization_name="New Startup" | |
| ) | |
| db.add(user) | |
| db.flush() | |
| initialize_startup_coa(db, user_id=user_id) | |
| db.commit() | |
| db.refresh(user) | |
| return user |