Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
26bbf4a
remove js from embedded
gkorland Aug 25, 2025
ffd0ed9
Merge branch 'staging' into toolbar-clean
gkorland Aug 25, 2025
bbb097b
Merge pull request #127 from FalkorDB/toolbar-clean
gkorland Aug 25, 2025
776b295
Merge branch 'main' into staging
gkorland Aug 25, 2025
f21bfb5
remove style from j2 files
gkorland Aug 25, 2025
8037ec5
remove style from j2 files
gkorland Aug 25, 2025
e4da6a8
remove style from j2 files
gkorland Aug 25, 2025
23b9f5a
Merge pull request #130 from FalkorDB/clean-j2
gkorland Aug 25, 2025
f687e0c
clean imports
gkorland Aug 25, 2025
ecf1d75
Merge branch 'staging' into clean-imports
gkorland Aug 25, 2025
ddb3bd3
Merge pull request #132 from FalkorDB/clean-imports
gkorland Aug 25, 2025
e60ddcc
Bump eslint from 9.33.0 to 9.34.0 in /app
dependabot[bot] Aug 26, 2025
ffe4b7b
initial commit with tokens
gkorland Aug 26, 2025
2b89e5d
Merge branch 'main' into login
gkorland Aug 26, 2025
cacd35e
Apply suggestion from @Copilot
gkorland Aug 26, 2025
87a34d2
read valid once
gkorland Aug 26, 2025
64986b1
Apply suggestion from @Copilot
gkorland Aug 26, 2025
9787d7f
clean deadcode
gkorland Aug 26, 2025
f17ba66
work with api token
gkorland Aug 26, 2025
4a29294
use BASE64 encodded for the graph name
gkorland Aug 26, 2025
51679ae
fix | with _
gkorland Aug 26, 2025
9dfab3f
Merge pull request #138 from FalkorDB/login
gkorland Aug 26, 2025
b477c97
Merge branch 'staging' into dependabot/npm_and_yarn/app/staging/eslin…
gkorland Aug 26, 2025
071f90d
Merge pull request #137 from FalkorDB/dependabot/npm_and_yarn/app/sta…
gkorland Aug 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 3 additions & 10 deletions api/app_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import logging
import os
import secrets

from dotenv import load_dotenv
from fastapi import FastAPI, Request, HTTPException
Expand All @@ -12,6 +11,7 @@
from starlette.middleware.base import BaseHTTPMiddleware

from api.auth.oauth_handlers import setup_oauth_handlers
from api.auth.user_management import SECRET_KEY
from api.routes.auth import auth_router, init_auth
from api.routes.graphs import graphs_router
from api.routes.database import database_router
Expand All @@ -20,7 +20,6 @@
load_dotenv()
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")


class SecurityMiddleware(BaseHTTPMiddleware):
"""Middleware for security checks including static file access"""

Expand Down Expand Up @@ -52,16 +51,10 @@ def create_app():
),
)

# Get secret key for sessions
secret_key = os.getenv("FASTAPI_SECRET_KEY")
if not secret_key:
secret_key = secrets.token_hex(32)
logging.warning("FASTAPI_SECRET_KEY not set, using generated key. Set this in production!")

# Add session middleware with explicit settings to ensure OAuth state persists
app.add_middleware(
SessionMiddleware,
secret_key=secret_key,
secret_key=SECRET_KEY,
session_cookie="qw_session",
same_site="lax", # allow top-level OAuth GET redirects to send cookies
https_only=False, # allow http on localhost in development
Expand Down Expand Up @@ -90,9 +83,9 @@ def create_app():
async def handle_oauth_error(request: Request, exc: Exception):
"""Handle OAuth-related errors gracefully"""
# Check if it's an OAuth-related error
# TODO check this scenario
if "token" in str(exc).lower() or "oauth" in str(exc).lower():
logging.warning("OAuth error occurred: %s", exc)
request.session.clear()
return RedirectResponse(url="/", status_code=302)

# If it's an HTTPException, re-raise so FastAPI handles it properly
Expand Down
4 changes: 2 additions & 2 deletions api/auth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
from .user_management import (
ensure_user_in_organizations,
update_identity_last_login,
validate_and_cache_user,
validate_user,
token_required,
)
from .oauth_handlers import setup_oauth_handlers

__all__ = [
"ensure_user_in_organizations",
"update_identity_last_login",
"validate_and_cache_user",
"validate_user",
"token_required",
"setup_oauth_handlers",
]
46 changes: 8 additions & 38 deletions api/auth/oauth_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import logging
from typing import Dict, Any

from fastapi import FastAPI, Request
from fastapi import FastAPI
from authlib.integrations.starlette_client import OAuth

from .user_management import ensure_user_in_organizations
Expand All @@ -19,62 +19,32 @@ def setup_oauth_handlers(app: FastAPI, oauth: OAuth):
# Store oauth in app state for access in routes
app.state.oauth = oauth

async def handle_google_callback(_request: Request,
_token: Dict[str, Any],
user_info: Dict[str, Any]):
"""Handle Google OAuth callback processing"""
async def handle_callback(provider: str, user_info: Dict[str, Any], api_token: str):
"""Handle Provider OAuth callback processing"""
try:
user_id = user_info.get("id")
email = user_info.get("email")
name = user_info.get("name")

# Validate required fields
if not user_id or not email:
logging.error("Missing required fields from Google OAuth response")
logging.error("Missing required fields from %s OAuth response", provider)
return False

# Check if identity exists in Organizations graph, create if new
_, _ = await ensure_user_in_organizations(
user_id,
email,
name,
"google",
provider,
api_token,
user_info.get("picture"),
)

return True
except Exception as exc: # capture exception for logging
Comment on lines 35 to 45
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use ensure_user_in_organizations result to decide success

Right now True is returned even if persistence fails. Wire the returned tuple to control flow so routes can react correctly.

-            _, _ = await ensure_user_in_organizations(
+            created, info = await ensure_user_in_organizations(
                 user_id,
                 email,
                 name,
                 provider,
                 api_token,
                 user_info.get("picture"),
             )
-
-            return True
+            if not info:
+                logging.error("Failed persisting identity for provider=%s email=%s", provider, email)
+                return False
+            return True
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
_, _ = await ensure_user_in_organizations(
user_id,
email,
name,
"google",
provider,
api_token,
user_info.get("picture"),
)
return True
except Exception as exc: # capture exception for logging
created, info = await ensure_user_in_organizations(
user_id,
email,
name,
provider,
api_token,
user_info.get("picture"),
)
if not info:
logging.error(
"Failed persisting identity for provider=%s email=%s",
provider,
email,
)
return False
return True
except Exception as exc: # capture exception for logging
🧰 Tools
🪛 GitHub Actions: Pylint

[warning] 45-45: Pylint: Catching too general exception (broad-exception-caught).

🤖 Prompt for AI Agents
In api/auth/oauth_handlers.py around lines 35 to 45, the code always returns
True even if ensure_user_in_organizations fails; capture and inspect the tuple
it returns and use that to decide the return value: assign the returned tuple to
meaningful variables (e.g., success, payload = await
ensure_user_in_organizations(...)), then if success is falsy return False (or
propagate the error) and only return True when success is truthy; keep the
existing exception logging behavior but ensure the normal flow uses the
function's result to determine success so callers can react correctly.

logging.error("Error handling Google OAuth callback: %s", exc)
return False

async def handle_github_callback(_request: Request,
_token: Dict[str, Any],
user_info: Dict[str, Any]):
"""Handle GitHub OAuth callback processing"""
try:
user_id = user_info.get("id")
email = user_info.get("email")
name = user_info.get("name") or user_info.get("login")

# Validate required fields
if not user_id or not email:
logging.error("Missing required fields from GitHub OAuth response")
return False

# Check if identity exists in Organizations graph, create if new
_, _ = await ensure_user_in_organizations(
user_id,
email,
name,
"github",
user_info.get("picture"),
)

return True
except Exception as exc: # capture exception for logging
logging.error("Error handling GitHub OAuth callback: %s", exc)
logging.error("Error handling %s OAuth callback: %s", provider, exc)
return False
Comment on lines +46 to 47
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Narrow exception handling and log stack traces

Addresses Pylint “broad-exception-caught” and improves debuggability by logging tracebacks. Keep a final broad catch if you want maximal safety.

-        except Exception as exc:  # capture exception for logging
-            logging.error("Error handling %s OAuth callback: %s", provider, exc)
-            return False
+        except (KeyError, ValueError) as exc:
+            logging.error("Invalid OAuth payload for %s: %s", provider, exc)
+            return False
+        except Exception as exc:  # pylint: disable=broad-except
+            logging.exception("Error handling %s OAuth callback", provider)
+            return False

Optionally, also import and catch Authlib’s OAuthError for even better specificity:


🏁 Script executed:

#!/bin/bash
# Verify if Authlib's OAuthError is available in this project version.
python - <<'PY'
try:
    from authlib.oauth2.rfc6749.errors import OAuthError
    print("OAuthError available")
except Exception as e:
    print("OAuthError not available:", e)
PY

Length of output: 62


🏁 Script executed:

#!/bin/bash
# Search for authlib in dependency files and codebase

echo "Listing potential dependency files:"
find . -maxdepth 2 -type f \( -name "requirements*.txt" -o -name "Pipfile" -o -name "setup.py" -o -name "pyproject.toml" \) -print

echo
echo "Checking for 'authlib' in requirements files:"
grep -R "authlib" -n requirements*.txt 2>/dev/null || echo "  → No authlib entry in requirements*.txt"

echo
echo "Checking for 'authlib' in Pipfile:"
grep -R "authlib" -n Pipfile 2>/dev/null || echo "  → No authlib entry in Pipfile"

echo
echo "Checking for 'authlib' in setup.py and pyproject.toml:"
grep -R "authlib" -n setup.py pyproject.toml 2>/dev/null || echo "  → No authlib entry in setup.py or pyproject.toml"

echo
echo "Searching codebase for any authlib imports or references:"
rg -n "authlib" . || echo "  → No authlib references found in code"

echo
echo "Searching codebase for OAuthError usage:"
rg -n "OAuthError" . || echo "  → No OAuthError references found in code"

Length of output: 1509


Narrow exception handling and log full tracebacks

To address the Pylint “broad-exception-caught” warning and improve debuggability, catch only the errors you expect and log full tracebacks for anything unexpected. Since Authlib is declared in your Pipfile (authlib ~=1.4.0) and imported elsewhere, you can also catch its OAuthError.

• Add at the top of api/auth/oauth_handlers.py (adjust the import path if your Authlib version differs):

from authlib.integrations.base_client.errors import OAuthError

• Replace the broad except Exception block with:

-        except Exception as exc:  # capture exception for logging
-            logging.error("Error handling %s OAuth callback: %s", provider, exc)
-            return False
+        except (KeyError, ValueError) as exc:
+            logging.error("Invalid OAuth payload for %s: %s", provider, exc)
+            return False
+        except OAuthError as exc:
+            logging.error("OAuth error during %s callback: %s", provider, exc)
+            return False
+        except Exception as exc:  # pylint: disable=broad-except
+            logging.exception("Unexpected error handling %s OAuth callback", provider)
+            return False

– The first two blocks handle common payload or client errors cleanly.
– The final block still guards against anything else, but now emits a full traceback to aid debugging.

🤖 Prompt for AI Agents
In api/auth/oauth_handlers.py around lines 46-47, replace the broad except
Exception block with narrow handlers: add an import for OAuthError from
authlib.integrations.base_client.errors at the top, then catch known errors
explicitly (e.g., except OAuthError: and except ValueError: or other expected
payload/client errors) and log concise error messages for those, and keep a
final generic except Exception that uses logging.exception(...) to record the
full traceback before returning False.


# Store handlers in app state for use in route callbacks
app.state.google_callback_handler = handle_google_callback
app.state.github_callback_handler = handle_github_callback
app.state.callback_handler = handle_callback
Loading
Loading