diff --git a/core/dashboard/routes.py b/core/dashboard/routes.py
index f279325..0660eed 100644
--- a/core/dashboard/routes.py
+++ b/core/dashboard/routes.py
@@ -2334,6 +2334,20 @@ async def auth_provider_redirect(request: Request) -> Response:
secure=os.environ.get("DASHBOARD_SECURE_COOKIE", "true").lower() == "true",
samesite="lax",
)
+
+ # Save return URL if provided (for OAuth consent flow redirect-back)
+ next_url = request.query_params.get("next", "")
+ if next_url:
+ response.set_cookie(
+ key="mcp_auth_next",
+ value=next_url,
+ max_age=600,
+ httponly=True,
+ secure=os.environ.get("DASHBOARD_SECURE_COOKIE", "true").lower() == "true",
+ samesite="lax",
+ path="/",
+ )
+
return response
except (RuntimeError, ValueError) as e:
logger.error("OAuth redirect failed for %s: %s", provider, e)
@@ -2445,15 +2459,25 @@ async def auth_callback(request: Request) -> Response:
role=user.get("role", "user"),
)
- response = RedirectResponse(url="/dashboard", status_code=303)
+ # Check for return URL (OAuth consent flow redirect-back)
+ next_url = request.cookies.get("mcp_auth_next", "")
+ # Validate: must be relative URL or same-origin to prevent open redirect
+ if next_url and next_url.startswith("/"):
+ redirect_to = next_url
+ else:
+ redirect_to = "/dashboard"
+
+ response = RedirectResponse(url=redirect_to, status_code=303)
dashboard_auth = get_dashboard_auth()
dashboard_auth.set_session_cookie(response, token)
response.delete_cookie(key="oauth_state")
+ response.delete_cookie(key="mcp_auth_next", path="/")
logger.info(
- "OAuth login successful: %s via %s",
+ "OAuth login successful: %s via %s (redirect=%s)",
user["email"],
provider,
+ redirect_to,
)
return response
diff --git a/core/templates/oauth/authorize.html b/core/templates/oauth/authorize.html
index cfcc6ad..9d96997 100644
--- a/core/templates/oauth/authorize.html
+++ b/core/templates/oauth/authorize.html
@@ -73,7 +73,52 @@
{% endif %}
-
+
+ {% if session_user %}
+
+
+
+
+
+
+
+ {% if lang == 'fa' %}وارد شده به عنوان{% else %}Logged in as{% endif %}
+
+
+ {{ session_user.name or session_user.email or 'User' }}
+ {% if session_user.email %}
+ ({{ session_user.email }})
+ {% endif %}
+
+
+
+
+
+
+ {% if lang == 'fa' %}
+ یا با کلید API وارد شوید
+ {% else %}
+ Or enter an API key instead
+ {% endif %}
+
+
+
+
+
+
+
+
{{ t.api_key_note }}
+
+
+ {% else %}
+
+ {% endif %}
@@ -131,29 +202,51 @@
{% block scripts %}
{% endblock %}
diff --git a/server.py b/server.py
index 661f79e..3ba9e3a 100644
--- a/server.py
+++ b/server.py
@@ -2394,6 +2394,37 @@ async def oauth_authorize(request: Request):
# Generate CSRF token
csrf_token = csrf_manager.generate_token()
+ # Detect existing dashboard session for session-based consent
+ session_user = None
+ try:
+ from core.dashboard.auth import get_dashboard_auth
+
+ dashboard_auth = get_dashboard_auth()
+
+ # Try OAuth user session first (GitHub/Google login)
+ user_session = dashboard_auth.get_user_session_from_request(request)
+ if user_session and user_session.get("user_id"):
+ session_user = {
+ "user_id": user_session["user_id"],
+ "email": user_session.get("email", ""),
+ "name": user_session.get("name", ""),
+ "role": user_session.get("role", "user"),
+ "type": "oauth_user",
+ }
+ else:
+ # Try admin session
+ admin_session = dashboard_auth.get_session_from_request(request)
+ if admin_session:
+ session_user = {
+ "user_id": "admin",
+ "email": "",
+ "name": "Admin",
+ "role": "admin",
+ "type": admin_session.user_type,
+ }
+ except Exception as e:
+ logger.debug(f"No dashboard session detected for OAuth consent: {e}")
+
# Get client info
from core.oauth import get_client_registry
@@ -2432,6 +2463,8 @@ async def oauth_authorize(request: Request):
"csrf_token": csrf_token,
"lang": lang, # Language code (en/fa)
"t": translations, # All translations for this language
+ "session_user": session_user,
+ "return_url": str(request.url),
},
)
@@ -2556,10 +2589,12 @@ async def oauth_authorize_confirm(request: Request):
state=params.get("state"),
)
- # Validate API Key
- api_key = params.get("api_key")
+ # Validate authentication (API Key or dashboard session)
+ api_key = params.get("api_key", "")
if not api_key:
- raise OAuthError(error="invalid_request", error_description="API Key is required")
+ raise OAuthError(
+ error="invalid_request", error_description="Authentication is required"
+ )
api_key_id = None
api_key_project_id = None
@@ -2567,13 +2602,12 @@ async def oauth_authorize_confirm(request: Request):
granted_scope = validated["scope"]
try:
- # Try as regular API key first
+ # Path 1: Project API key (cmp_)
if api_key.startswith("cmp_"):
- # Validate without project/scope check (we'll use its values)
key_id = api_key_manager.validate_key(
api_key,
- project_id="*", # Skip project check
- required_scope="read", # Skip scope check
+ project_id="*",
+ required_scope="read",
skip_project_check=True,
)
api_key_info = api_key_manager.keys.get(key_id)
@@ -2581,9 +2615,67 @@ async def oauth_authorize_confirm(request: Request):
api_key_project_id = api_key_info.project_id
api_key_scope = api_key_info.scope
- # Try as Master API Key
+ # Path 2: User API key (mhu_)
+ elif api_key.startswith("mhu_"):
+ from core.user_keys import get_user_key_manager
+
+ user_key_mgr = get_user_key_manager()
+ key_info = await user_key_mgr.validate_key(api_key)
+ if key_info:
+ api_key_id = f"user:{key_info['user_id']}"
+ api_key_project_id = "*"
+ api_key_scope = key_info.get("scopes", "read write")
+ logger.info(
+ f"OAuth authorization: User API key validated - "
+ f"user_id={key_info['user_id']}, scope={api_key_scope}"
+ )
+ else:
+ raise OAuthError(
+ error="access_denied",
+ error_description="Invalid or expired User API Key.",
+ )
+
+ # Path 3: Dashboard session (social login)
+ elif api_key == "__session__":
+ from core.dashboard.auth import get_dashboard_auth
+
+ dashboard_auth = get_dashboard_auth()
+
+ # Try OAuth user session (GitHub/Google)
+ user_session = dashboard_auth.get_user_session_from_request(request)
+ if user_session and user_session.get("user_id"):
+ user_role = user_session.get("role", "user")
+ api_key_id = f"user:{user_session['user_id']}"
+ api_key_project_id = "*"
+ if user_role == "admin":
+ api_key_scope = "read write admin"
+ else:
+ api_key_scope = "read write"
+ logger.info(
+ f"OAuth authorization: Session-based consent - "
+ f"user_id={user_session['user_id']}, "
+ f"email={user_session.get('email', '')}, "
+ f"role={user_role}, scope={api_key_scope}"
+ )
+ else:
+ # Try admin session
+ admin_session = dashboard_auth.get_session_from_request(request)
+ if admin_session:
+ api_key_id = f"admin:{admin_session.session_id}"
+ api_key_project_id = "*"
+ api_key_scope = "read write admin"
+ logger.info(
+ f"OAuth authorization: Admin session consent - "
+ f"type={admin_session.user_type}"
+ )
+ else:
+ raise OAuthError(
+ error="access_denied",
+ error_description="Session expired. Please log in again.",
+ )
+
+ # Path 4: Master API Key
elif auth_manager.validate_master_key(api_key):
- # Master key → Full access
api_key_id = "master"
api_key_project_id = "*"
api_key_scope = "read write admin"