Ali2206 commited on
Commit
740f610
·
verified ·
1 Parent(s): 904089c

Update core/security.py

Browse files
Files changed (1) hide show
  1. core/security.py +45 -78
core/security.py CHANGED
@@ -1,94 +1,61 @@
1
  from datetime import datetime, timedelta
2
- from fastapi import HTTPException, status, Request, Depends
3
- from fastapi.security import OAuth2PasswordBearer
4
  from jose import jwt, JWTError
5
- from db.mongo import users_collection
 
6
  from core.config import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES
 
7
  import logging
8
- from typing import Optional
9
 
10
  logger = logging.getLogger(__name__)
11
 
12
- oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login")
 
 
 
 
 
 
13
 
14
- def create_access_token(data: dict) -> str:
15
- try:
16
- to_encode = data.copy()
17
- expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
18
- to_encode.update({"exp": expire})
19
- encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
20
- logger.info(f"Token created for {data.get('sub')}")
21
- return encoded_jwt
22
- except Exception as e:
23
- logger.error(f"Token creation failed: {str(e)}")
24
- raise HTTPException(
25
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
26
- detail="Token creation failed"
27
- )
28
 
29
- async def validate_token(token: str) -> dict:
30
- try:
31
- if not token:
32
- logger.error("Empty token provided")
33
- raise HTTPException(
34
- status_code=status.HTTP_401_UNAUTHORIZED,
35
- detail="No token provided"
36
- )
 
 
37
 
38
- # Handle cases where 'Bearer ' prefix might be present
39
- if token.startswith("Bearer "):
40
- token = token[7:]
41
- logger.debug("Removed 'Bearer ' prefix from token")
42
 
 
 
 
 
 
43
  payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
 
 
44
  email = payload.get("sub")
45
  if not email:
46
- logger.error("Token missing 'sub' claim")
47
- raise HTTPException(
48
- status_code=status.HTTP_401_UNAUTHORIZED,
49
- detail="Invalid token format"
50
- )
51
-
52
- logger.info(f"Token validated for {email}")
53
- return payload
54
-
55
- except jwt.ExpiredSignatureError:
56
- logger.error("Token expired")
57
- raise HTTPException(
58
- status_code=status.HTTP_401_UNAUTHORIZED,
59
- detail="Token expired"
60
- )
61
  except JWTError as e:
62
- logger.error(f"Token validation failed: {str(e)}")
63
- raise HTTPException(
64
- status_code=status.HTTP_401_UNAUTHORIZED,
65
- detail="Could not validate credentials"
66
- )
67
 
68
- async def get_current_user(request: Request, token: str = Depends(oauth2_scheme)) -> dict:
69
- logger.info(f"Incoming request headers: {dict(request.headers)}")
70
- logger.info(f"Raw token received: {token[:15]}...") # Log first 15 chars for security
71
-
72
- try:
73
- payload = await validate_token(token)
74
- email = payload.get("sub")
75
-
76
- user = await users_collection.find_one({"email": email})
77
- if not user:
78
- logger.error(f"User not found in DB: {email}")
79
- raise HTTPException(
80
- status_code=status.HTTP_404_NOT_FOUND,
81
- detail="User not found"
82
- )
83
-
84
- logger.info(f"User authenticated: {email}")
85
- return user
86
-
87
- except HTTPException:
88
- raise
89
- except Exception as e:
90
- logger.error(f"Unexpected error in get_current_user: {str(e)}")
91
- raise HTTPException(
92
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
93
- detail="Internal server error"
94
- )
 
1
  from datetime import datetime, timedelta
2
+ from passlib.context import CryptContext
 
3
  from jose import jwt, JWTError
4
+ from fastapi import Depends, HTTPException, status
5
+ from fastapi.security import OAuth2PasswordBearer
6
  from core.config import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES
7
+ from db.mongo import users_collection
8
  import logging
9
+ from fastapi import Request
10
 
11
  logger = logging.getLogger(__name__)
12
 
13
+ # OAuth2 setup
14
+ oauth2_scheme = OAuth2PasswordBearer(
15
+ tokenUrl="/auth/login", # Correct path
16
+ scheme_name="JWT"
17
+ )
18
+ # Password hashing context
19
+ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
20
 
21
+ # Hash a plain password
22
+ def hash_password(password: str) -> str:
23
+ return pwd_context.hash(password)
 
 
 
 
 
 
 
 
 
 
 
24
 
25
+ # Verify a plain password against the hash
26
+ def verify_password(plain: str, hashed: str) -> bool:
27
+ return pwd_context.verify(plain, hashed)
28
+
29
+ # Create a JWT access token
30
+ def create_access_token(data: dict, expires_delta: timedelta = None):
31
+ to_encode = data.copy()
32
+ expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
33
+ to_encode.update({"exp": expire})
34
+ return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
35
 
36
+ # Get the current user from the JWT token
37
+ async def get_current_user(request: Request, token: str = Depends(oauth2_scheme)):
38
+ print("🧪 Request headers:", dict(request.headers))
39
+ print("🔐 Raw token received:", token)
40
 
41
+ if not token:
42
+ print("❌ No token received")
43
+ raise HTTPException(status_code=401, detail="No token provided")
44
+
45
+ try:
46
  payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
47
+ print("🧠 Token payload:", payload)
48
+
49
  email = payload.get("sub")
50
  if not email:
51
+ raise HTTPException(status_code=401, detail="Invalid token: missing subject")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  except JWTError as e:
53
+ print(" JWT decode error:", str(e))
54
+ raise HTTPException(status_code=401, detail="Could not validate token")
 
 
 
55
 
56
+ user = await users_collection.find_one({"email": email})
57
+ if not user:
58
+ raise HTTPException(status_code=404, detail="User not found")
59
+
60
+ print("✅ Authenticated user:", user["email"])
61
+ return user