revai-api / app /routers /auth.py
Shaankar39's picture
Deploy RevAI API
3d1332e
Raw
History Blame Contribute Delete
3.52 kB
import uuid
import datetime
import hashlib
import os
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from jose import jwt
from app.database import get_db
from app.models.user import User
from app.models.apikey import APIKey
from app.dependencies import hash_api_key, get_current_user
from app.schemas import UserRegister, UserLogin, TokenResponse, APIKeyResponse
from app.config import get_settings
router = APIRouter(prefix="/v1/auth", tags=["auth"])
settings = get_settings()
def hash_password(password: str) -> str:
salt = os.urandom(16).hex()
h = hashlib.sha256((password + salt).encode()).hexdigest()
return f"{salt}${h}"
def verify_password(password: str, hashed: str) -> bool:
salt, h = hashed.split("$", 1)
return hashlib.sha256((password + salt).encode()).hexdigest() == h
def generate_api_key() -> tuple:
raw = f"revai_live_{uuid.uuid4().hex}{uuid.uuid4().hex[:8]}"
return raw, hash_api_key(raw)
def create_token(user: User) -> str:
payload = {
"sub": user.id,
"email": user.email,
"tier": user.tier,
"exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=settings.access_token_expire_minutes),
}
return jwt.encode(payload, settings.secret_key, algorithm=settings.algorithm)
@router.post("/register", response_model=TokenResponse)
def register(body: UserRegister, db: Session = Depends(get_db)):
existing = db.query(User).filter(User.email == body.email).first()
if existing:
raise HTTPException(status_code=409, detail="Email already registered")
user = User(
email=body.email,
hashed_password=hash_password(body.password),
name=body.name,
)
db.add(user)
db.flush()
raw_key, key_hash = generate_api_key()
api_key = APIKey(
user_id=user.id,
key_hash=key_hash,
prefix=raw_key[:20] + "...",
)
db.add(api_key)
db.commit()
token = create_token(user)
return TokenResponse(
access_token=token,
user_id=user.id,
email=user.email,
tier=user.tier,
api_key=raw_key,
)
@router.post("/login", response_model=TokenResponse)
def login(body: UserLogin, db: Session = Depends(get_db)):
user = db.query(User).filter(User.email == body.email).first()
if not user or not verify_password(body.password, user.hashed_password):
raise HTTPException(status_code=401, detail="Invalid email or password")
# Return existing active key or create new one
api_key = db.query(APIKey).filter(
APIKey.user_id == user.id, APIKey.is_active == True
).first()
raw_key = None
if not api_key:
raw_key, key_hash = generate_api_key()
api_key = APIKey(user_id=user.id, key_hash=key_hash, prefix=raw_key[:20] + "...")
db.add(api_key)
db.commit()
raw_key = raw_key
token = create_token(user)
return TokenResponse(
access_token=token,
user_id=user.id,
email=user.email,
tier=user.tier,
api_key=raw_key,
)
@router.get("/keys", response_model=list[APIKeyResponse])
def list_api_keys(user: User = Depends(get_current_user),
db: Session = Depends(get_db)):
keys = db.query(APIKey).filter(APIKey.user_id == user.id).all()
return [APIKeyResponse(
id=k.id, prefix=k.prefix, name=k.name,
is_active=k.is_active, created_at=k.created_at,
last_used_at=k.last_used_at
) for k in keys]