-
Notifications
You must be signed in to change notification settings - Fork 4
ccc #50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
ccc #50
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,147 @@ | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| from fastapi import APIRouter, HTTPException, status, Depends | ||||||||||||||||||||||||||||||||||||||
| from typing import Dict, Any, Optional | ||||||||||||||||||||||||||||||||||||||
| import jwt | ||||||||||||||||||||||||||||||||||||||
| from datetime import datetime, timedelta | ||||||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| from .models import UserResponse, TokenResponse | ||||||||||||||||||||||||||||||||||||||
| from .firebase_auth import firebase_auth | ||||||||||||||||||||||||||||||||||||||
| from .dependencies import get_current_user | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| router = APIRouter(prefix="/users", tags=["users"]) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| class UserManager: | ||||||||||||||||||||||||||||||||||||||
| def __init__(self): | ||||||||||||||||||||||||||||||||||||||
| self.jwt_secret = os.getenv("JWT_SECRET", "default-secret-key") | ||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hardcoded JWT SecretJWT secret falls back to hardcoded default value when environment variable missing. Attackers knowing this default can forge tokens in misconfigured environments, making production deployments without proper JWT_SECRET configuration vulnerable to authentication bypass through token forgery. Commitable Suggestion
Suggested change
Standards
|
||||||||||||||||||||||||||||||||||||||
| self.jwt_algorithm = "HS256" | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+16
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find . -name "user_management.py" -type fRepository: coderabbit-test/pr-reviewer Length of output: 91 🏁 Script executed: # Search for the file in common locations
git ls-files | grep -i user_managementRepository: coderabbit-test/pr-reviewer Length of output: 89 🏁 Script executed: cat -n user_management.py | head -50Repository: coderabbit-test/pr-reviewer Length of output: 1979 🏁 Script executed: # Search for JWT_SECRET references in the codebase
rg "JWT_SECRET" -A 2 -B 2Repository: coderabbit-test/pr-reviewer Length of output: 1206 🏁 Script executed: # Check for environment validation or startup checks
rg "RuntimeError|ValueError|raise.*env" user_management.pyRepository: coderabbit-test/pr-reviewer Length of output: 53 🏁 Script executed: # Look for deployment/config files
fd -e "\.env" -e "requirements.txt" -e "docker" -e "compose" -e "conftest" -o -name ".github" -o -name "config*"Repository: coderabbit-test/pr-reviewer Length of output: 301 🏁 Script executed: cat -n test_auth.py | head -80Repository: coderabbit-test/pr-reviewer Length of output: 2947 🏁 Script executed: # Search for how required_vars validation is implemented
rg "required_vars" -A 5 -B 2Repository: coderabbit-test/pr-reviewer Length of output: 670 🏁 Script executed: # Check for main/startup validation
rg "def main|if __name__|@app.on_event|@asynccontextmanager" -A 3Repository: coderabbit-test/pr-reviewer Length of output: 637 🏁 Script executed: # Check if there's env validation in conftest or similar
fd -e "conftest.py" -o -e "main.py" -o -e "__main__.py" | xargs -I {} cat {}Repository: coderabbit-test/pr-reviewer Length of output: 187 🏁 Script executed: # Check app/main.py for startup validation
cat -n app/main.py 2>/dev/null | head -60Repository: coderabbit-test/pr-reviewer Length of output: 1860 🏁 Script executed: # If app/main.py doesn't exist, check common startup patterns
find . -name "main.py" -o -name "asgi.py" | xargs cat -n 2>/dev/null | head -80Repository: coderabbit-test/pr-reviewer Length of output: 2631 🏁 Script executed: # Check if app/auth/firebase_auth.py has same fallback pattern
rg -A 5 "class FirebaseAuthService" app/auth/firebase_auth.pyRepository: coderabbit-test/pr-reviewer Length of output: 317 Avoid fallback to a hard-coded JWT secret
Replace with: - self.jwt_secret = os.getenv("JWT_SECRET", "default-secret-key")
+ self.jwt_secret = os.getenv("JWT_SECRET")
+ if not self.jwt_secret:
+ raise RuntimeError("JWT_SECRET must be set in environment")Apply the same fix to 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| async def update_user_profile( | ||||||||||||||||||||||||||||||||||||||
| self, | ||||||||||||||||||||||||||||||||||||||
| user_id: str, | ||||||||||||||||||||||||||||||||||||||
| first_name: str, | ||||||||||||||||||||||||||||||||||||||
| last_name: str | ||||||||||||||||||||||||||||||||||||||
| ) -> Dict[str, Any]: | ||||||||||||||||||||||||||||||||||||||
| """Update user profile information""" | ||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||
| from firebase_admin import auth | ||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Update display name | ||||||||||||||||||||||||||||||||||||||
| auth.update_user( | ||||||||||||||||||||||||||||||||||||||
| user_id, | ||||||||||||||||||||||||||||||||||||||
| display_name=f"{first_name} {last_name}" | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| user_record = auth.get_user(user_id) | ||||||||||||||||||||||||||||||||||||||
| current_claims = user_record.custom_claims or {} | ||||||||||||||||||||||||||||||||||||||
| current_claims["first_name"] = first_name | ||||||||||||||||||||||||||||||||||||||
| current_claims["last_name"] = last_name | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+38
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The custom claims for
Suggested change
Comment on lines
+37
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Profile Claims Not SavedThe code modifies a local dictionary for custom claims but never calls auth.set_custom_user_claims() to persist these changes to Firebase. This results in a silent failure where user profile data is not stored in the token claims, leading to incorrect application behavior and data state. Commitable Suggestion
Suggested change
Standards
Comment on lines
+36
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing Custom Claims UpdateProfile update modifies custom claims dictionary locally but never persists changes to Firebase using set_custom_user_claims. User profile updates appear successful but claims remain unchanged in Firebase authentication system, causing data inconsistency between displayed profile and actual authentication claims. Standards
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: In Severity Level: Minor
Suggested change
Why it matters? ⭐The code mutates the local current_claims dict but never calls auth.set_custom_user_claims(user_id, current_claims), so Firebase never persists these claim changes. This is a logic bug: tokens and Firebase-stored claims will not reflect the update unless claims are written back. Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** user_management.py
**Line:** 40:40
**Comment:**
*Logic Error: In `update_user_profile`, the custom claims dictionary is modified in memory but never written back to Firebase, so the updated `first_name` and `last_name` will not actually be reflected in subsequent token-based user data.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. |
||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||
| "id": user_id, | ||||||||||||||||||||||||||||||||||||||
| "first_name": first_name, | ||||||||||||||||||||||||||||||||||||||
| "last_name": last_name, | ||||||||||||||||||||||||||||||||||||||
| "updated_at": datetime.utcnow().isoformat() | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| except Exception as e: | ||||||||||||||||||||||||||||||||||||||
| raise Exception(f"Failed to update user: {str(e)}") | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+20
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find . -name "user_management.py" -type fRepository: coderabbit-test/pr-reviewer Length of output: 91 🏁 Script executed: cat -n ./user_management.pyRepository: coderabbit-test/pr-reviewer Length of output: 5725 🌐 Web query:
💡 Result: Summary — Python Admin SDK: auth.set_custom_user_claims(uid, custom_claims, app=None)
Docs / reference (official):
If you want, I can paste the exact doc snippet or show how to check a user's current claims and update them incrementally. Citations:
Custom claims are never persisted and exception handling is too broad The code mutates Persist the claims and use appropriate error handling: current_claims = user_record.custom_claims or {}
current_claims["first_name"] = first_name
current_claims["last_name"] = last_name
+ auth.set_custom_user_claims(user_id, current_claims)
return {
"id": user_id,
"first_name": first_name,
"last_name": last_name,
"updated_at": datetime.utcnow().isoformat()
}
- except Exception as e:
- raise Exception(f"Failed to update user: {str(e)}")
+ except Exception as e:
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail="Failed to update user profile",
+ ) from e
🧰 Tools🪛 Ruff (0.14.8)47-47: Do not catch blind exception: (BLE001) 48-48: Within an (B904) 48-48: Create your own exception (TRY002) 48-48: Avoid specifying long messages outside the exception class (TRY003) 48-48: Use explicit conversion flag Replace with conversion flag (RUF010) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| async def refresh_user_token(self, refresh_token: str) -> Optional[str]: | ||||||||||||||||||||||||||||||||||||||
| """Refresh access token - ISSUE: Skips validation""" | ||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||
| payload = jwt.decode( | ||||||||||||||||||||||||||||||||||||||
| refresh_token, | ||||||||||||||||||||||||||||||||||||||
| self.jwt_secret, | ||||||||||||||||||||||||||||||||||||||
| algorithms=[self.jwt_algorithm], | ||||||||||||||||||||||||||||||||||||||
| options={"verify_exp": False} | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+53
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A critical security vulnerability exists here. By setting payload = jwt.decode(
refresh_token,
self.jwt_secret,
algorithms=[self.jwt_algorithm]
)
Comment on lines
+53
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. JWT Validation BypassToken refresh function disables expiration verification allowing expired tokens to be refreshed indefinitely. Attackers can reuse compromised refresh tokens beyond their intended lifetime, bypassing token expiration security controls and enabling persistent unauthorized access. Commitable Suggestion
Suggested change
Standards
Comment on lines
+57
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: The refresh token is decoded with expiration checks disabled and without verifying that it is actually a refresh token, allowing expired or wrong‑type JWTs to be exchanged for new access tokens and weakening authentication security. [security] Severity Level: Critical 🚨
Suggested change
Why it matters? ⭐The current implementation explicitly disables expiration verification and doesn't verify the token 'type' is a refresh token. That allows expired or access tokens to be exchanged for fresh access tokens — a clear security issue. The suggested change to re-enable expiration checks and assert payload["type"] == "refresh" is a correct and necessary mitigation. Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** user_management.py
**Line:** 57:58
**Comment:**
*Security: The refresh token is decoded with expiration checks disabled and without verifying that it is actually a refresh token, allowing expired or wrong‑type JWTs to be exchanged for new access tokens and weakening authentication security.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise. |
||||||||||||||||||||||||||||||||||||||
| user_id = payload.get("user_id") | ||||||||||||||||||||||||||||||||||||||
| email = payload.get("email") | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| new_payload = { | ||||||||||||||||||||||||||||||||||||||
| "user_id": user_id, | ||||||||||||||||||||||||||||||||||||||
| "email": email, | ||||||||||||||||||||||||||||||||||||||
| "exp": datetime.utcnow() + timedelta(minutes=10), | ||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Short Token ExpiryAccess tokens expire in only 10 minutes causing frequent re-authentication requests that may impact user experience. Short expiry combined with insecure refresh mechanism creates usability issues while maintaining security vulnerabilities. Standards
|
||||||||||||||||||||||||||||||||||||||
| "iat": datetime.utcnow(), | ||||||||||||||||||||||||||||||||||||||
| "type": "access" | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return jwt.encode(new_payload, self.jwt_secret, algorithm=self.jwt_algorithm) | ||||||||||||||||||||||||||||||||||||||
| except Exception as e: | ||||||||||||||||||||||||||||||||||||||
| print(f"Token refresh failed: {e}") | ||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+71
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using except Exception:
import logging
logging.exception("Token refresh failed")
return None
Comment on lines
+71
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Improper Exception HandlingMethods like refresh_user_token and verify_user_token catch generic exceptions, print them to the console, and return None. This practice hides the error's context from the calling API layer and complicates error handling logic. It is better to raise specific application-level exceptions or let them propagate to a centralized handler. Standards
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| async def verify_user_token(self, token: str) -> Optional[Dict[str, Any]]: | ||||||||||||||||||||||||||||||||||||||
| """Verify JWT token - ISSUE: Using JWT instead of Firebase""" | ||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||
| payload = jwt.decode( | ||||||||||||||||||||||||||||||||||||||
| token, | ||||||||||||||||||||||||||||||||||||||
| self.jwt_secret, | ||||||||||||||||||||||||||||||||||||||
| algorithms=[self.jwt_algorithm] | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+78
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Firebase Auth BypassCustom JWT verification bypasses Firebase authentication system using local secret instead of Firebase token validation. Attackers can forge tokens with knowledge of JWT secret, circumventing Firebase security controls and creating a parallel authentication system vulnerable to token forgery attacks. Commitable Suggestion
Suggested change
Standards
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||
| "uid": payload.get("user_id"), | ||||||||||||||||||||||||||||||||||||||
| "email": payload.get("email"), | ||||||||||||||||||||||||||||||||||||||
| "first_name": payload.get("first_name", ""), | ||||||||||||||||||||||||||||||||||||||
| "last_name": payload.get("last_name", ""), | ||||||||||||||||||||||||||||||||||||||
| "role": payload.get("role", "user") | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| except Exception as e: | ||||||||||||||||||||||||||||||||||||||
| print(f"Token verification failed: {e}") | ||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+75
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method implements custom JWT verification, which is inconsistent with the rest of the application that seems to rely on Firebase for authentication (e.g.,
Comment on lines
+91
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using except Exception:
import logging
logging.exception("Token verification failed")
return None
Comment on lines
+75
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find . -type f -name "*.py" | head -20Repository: coderabbit-test/pr-reviewer Length of output: 311 🏁 Script executed: git ls-files | grep -E "(user_management|auth)" | head -20Repository: coderabbit-test/pr-reviewer Length of output: 212 🏁 Script executed: wc -l user_management.py app/auth/*.pyRepository: coderabbit-test/pr-reviewer Length of output: 247 🏁 Script executed: cat -n user_management.pyRepository: coderabbit-test/pr-reviewer Length of output: 5725 🏁 Script executed: cat -n app/auth/dependencies.pyRepository: coderabbit-test/pr-reviewer Length of output: 2627 🏁 Script executed: cat -n app/auth/firebase_auth.pyRepository: coderabbit-test/pr-reviewer Length of output: 7451 🏁 Script executed: rg "verify_user_token|refresh_user_token" --type py -nRepository: coderabbit-test/pr-reviewer Length of output: 445 🏁 Script executed: cat -n app/auth/routes.pyRepository: coderabbit-test/pr-reviewer Length of output: 4886 🏁 Script executed: rg "print\(" user_management.py -nRepository: coderabbit-test/pr-reviewer Length of output: 177 🏁 Script executed: rg "refresh_token_endpoint|validate_token" --type py -B2 -A5Repository: coderabbit-test/pr-reviewer Length of output: 899 Remove custom JWT validation and consolidate to Firebase authentication using existing dependencies
The codebase already has the proper pattern in place: -@router.get("/validate")
-async def validate_token(token: str):
- """Validate token using custom verification"""
- user_data = await user_manager.verify_user_token(token)
-
- if not user_data:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Invalid token"
- )
-
- return {"valid": True, "user": user_data}
+@router.get("/validate")
+async def validate_token(current_user: Dict[str, Any] = Depends(get_current_user)):
+ """Validate current Firebase token and return user data."""
+ return {"valid": True, "user": current_user}Also replace the
🧰 Tools🪛 Ruff (0.14.8)91-91: Do not catch blind exception: (BLE001) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| user_manager = UserManager() | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| @router.put("/profile", response_model=UserResponse) | ||||||||||||||||||||||||||||||||||||||
| async def update_profile( | ||||||||||||||||||||||||||||||||||||||
| first_name: str, | ||||||||||||||||||||||||||||||||||||||
| last_name: str, | ||||||||||||||||||||||||||||||||||||||
| current_user: Dict[str, Any] = Depends(get_current_user) | ||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||
| """Update current user's profile""" | ||||||||||||||||||||||||||||||||||||||
| result = await user_manager.update_user_profile( | ||||||||||||||||||||||||||||||||||||||
| user_id=current_user["uid"], | ||||||||||||||||||||||||||||||||||||||
| first_name=first_name, | ||||||||||||||||||||||||||||||||||||||
| last_name=last_name | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return UserResponse( | ||||||||||||||||||||||||||||||||||||||
| id=result["id"], | ||||||||||||||||||||||||||||||||||||||
| email=current_user["email"], | ||||||||||||||||||||||||||||||||||||||
| first_name=result["first_name"], | ||||||||||||||||||||||||||||||||||||||
| last_name=result["last_name"], | ||||||||||||||||||||||||||||||||||||||
| is_active=True, | ||||||||||||||||||||||||||||||||||||||
| created_at=result["updated_at"] | ||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect Timestamp FieldThe created_at field in the response object is populated with the updated_at value. This is semantically incorrect and can lead to data inconsistencies or bugs in client applications that rely on this field to represent the user's creation time. Standards
|
||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| @router.post("/refresh-token", response_model=TokenResponse) | ||||||||||||||||||||||||||||||||||||||
| async def refresh_token_endpoint(refresh_token: str): | ||||||||||||||||||||||||||||||||||||||
| """Refresh access token using custom logic""" | ||||||||||||||||||||||||||||||||||||||
| new_token = await user_manager.refresh_user_token(refresh_token) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if not new_token: | ||||||||||||||||||||||||||||||||||||||
| raise HTTPException( | ||||||||||||||||||||||||||||||||||||||
| status_code=status.HTTP_401_UNAUTHORIZED, | ||||||||||||||||||||||||||||||||||||||
| detail="Invalid refresh token" | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return TokenResponse(access_token=new_token) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| @router.get("/validate") | ||||||||||||||||||||||||||||||||||||||
| async def validate_token(token: str): | ||||||||||||||||||||||||||||||||||||||
| """Validate token using custom verification""" | ||||||||||||||||||||||||||||||||||||||
| user_data = await user_manager.verify_user_token(token) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if not user_data: | ||||||||||||||||||||||||||||||||||||||
| raise HTTPException( | ||||||||||||||||||||||||||||||||||||||
| status_code=status.HTTP_401_UNAUTHORIZED, | ||||||||||||||||||||||||||||||||||||||
| detail="Invalid token" | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return {"valid": True, "user": user_data} | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a default hardcoded secret key
default-secret-keyis a major security risk. If theJWT_SECRETenvironment variable is not set, the application will fall back to this known, insecure key, making your JWTs easy to forge. It's better to fail fast if the secret is not configured. This change will cause the application to raise aKeyErroron startup ifJWT_SECRETis not set, which is the desired behavior for critical configuration.