ashnaali22/phase-3-h2
0
1from sqlalchemy.orm import Session
2from fastapi import Depends, HTTPException, Cookie, Header, status
3from typing import Optional
4from jose import JWTError
5from backend.database.connection import SessionLocal
6from backend.utils.jwt import decode_token
7
8
9def get_db() -> Session:
10 db = SessionLocal()
11 try:
12 yield db
13 finally:
14 db.close()
15
16
17def get_current_user_id(
18 auth_token: Optional[str] = Cookie(None),
19 authorization: Optional[str] = Header(None)
20) -> str:
21 """
22 Extract user_id from JWT token (Cookie OR Authorization header).
23
24 Supports both authentication methods for cross-domain compatibility:
25 1. Cookie: auth_token (same-site requests)
26 2. Authorization header: Bearer token (cross-site requests)
27
28 Args:
29 auth_token: JWT token from Cookie header
30 authorization: Bearer token from Authorization header
31
32 Returns:
33 user_id: User UUID as string
34
35 Raises:
36 HTTPException 401: If token is missing, invalid, or expired
37
38 Cache Behavior:
39 - Uses JWT caching from decode_token (5-minute TTL)
40 - Cache hit: <5ms response time
41 - Cache miss: ~40ms for JWT validation
42 """
43 import logging
44 logger = logging.getLogger(__name__)
45
46 # Debug logging
47 logger.info(f"[AUTH] Cookie token present: {bool(auth_token)}")
48 logger.info(f"[AUTH] Authorization header present: {bool(authorization)}")
49 if authorization:
50 logger.info(f"[AUTH] Authorization header value: {authorization[:30]}...")
51
52 # Try Authorization header first (for cross-domain requests)
53 token = None
54 if authorization and authorization.startswith("Bearer "):
55 token = authorization.replace("Bearer ", "")
56 logger.info(f"[AUTH] Extracted token from Authorization header: {token[:20]}...")
57 # Fall back to cookie (for same-site requests)
58 elif auth_token:
59 token = auth_token
60 logger.info(f"[AUTH] Using token from cookie: {token[:20]}...")
61
62 if not token:
63 logger.error("[AUTH] No token found in either Authorization header or cookie!")
64 raise HTTPException(
65 status_code=status.HTTP_401_UNAUTHORIZED,
66 detail="Authentication required. Please login to access this resource."
67 )
68
69 try:
70 # decode_token already implements caching with 5-minute TTL
71 # It will raise JWTError if token is invalid, expired, or malformed
72 payload = decode_token(token, use_cache=True)
73 user_id = payload.get("sub")
74
75 if not user_id:
76 raise HTTPException(
77 status_code=status.HTTP_401_UNAUTHORIZED,
78 detail="Invalid token: missing user identifier"
79 )
80
81 return user_id
82
83 except JWTError as e:
84 raise HTTPException(
85 status_code=status.HTTP_401_UNAUTHORIZED,
86 detail=f"Invalid or expired token: {str(e)}"
87 )
88 except ValueError as e:
89 raise HTTPException(
90 status_code=status.HTTP_401_UNAUTHORIZED,
91 detail=f"Token validation failed: {str(e)}"
92 )
93 