@@ -3919,7 +3919,28 @@ async def prepare_rust_mcp_tool_execution(
39193919 # plugin invocation enforces the requirement locally with an actionable error.
39203920 oauth_authcode_no_db_token = False
39213921
3922- if has_gateway and gateway_auth_type == "oauth" and isinstance (gateway_oauth_config , dict ) and gateway_oauth_config :
3922+ # Per-user personal credentials always take priority over
3923+ # gateway-level OAuth tokens.
3924+ user_credential_headers = None
3925+ if has_gateway and app_user_email and gateway_id_str :
3926+ try :
3927+ from mcpgateway .services .credential_storage_service import CredentialStorageService # pylint: disable=import-outside-toplevel
3928+
3929+ with fresh_db_session () as cred_db :
3930+ cred_service = CredentialStorageService (cred_db )
3931+ cred_record = await cred_service .get_credential_record (gateway_id_str , app_user_email )
3932+ if cred_record :
3933+ cred_value = await cred_service .get_credential (gateway_id_str , app_user_email )
3934+ if cred_value :
3935+ user_credential_headers = CredentialStorageService .build_auth_headers (
3936+ cred_record .credential_type , cred_value , gateway_auth_type
3937+ )
3938+ except Exception as e :
3939+ logger .debug (f"Failed to check personal credentials for gateway { gateway_name } : { e } " )
3940+
3941+ if user_credential_headers :
3942+ headers = user_credential_headers
3943+ elif has_gateway and gateway_auth_type == "oauth" and isinstance (gateway_oauth_config , dict ) and gateway_oauth_config :
39233944 grant_type = gateway_oauth_config .get ("grant_type" , "client_credentials" )
39243945 if grant_type == "authorization_code" :
39253946 try :
@@ -3957,28 +3978,8 @@ async def prepare_rust_mcp_tool_execution(
39573978 logger .error (f"Failed to obtain OAuth access token for gateway { gateway_name } : { e } " )
39583979 raise ToolInvocationError (f"OAuth authentication failed for gateway: { str (e )} " )
39593980 else :
3960- # Check for per-user personal credentials before falling back to shared gateway auth
3961- user_credential_headers = None
3962- if has_gateway and app_user_email and gateway_id_str :
3963- try :
3964- from mcpgateway .services .credential_storage_service import CredentialStorageService # pylint: disable=import-outside-toplevel
3965-
3966- with fresh_db_session () as cred_db :
3967- cred_service = CredentialStorageService (cred_db )
3968- cred_record = await cred_service .get_credential_record (gateway_id_str , app_user_email )
3969- if cred_record :
3970- cred_value = await cred_service .get_credential (gateway_id_str , app_user_email )
3971- if cred_value :
3972- user_credential_headers = CredentialStorageService .build_auth_headers (
3973- cred_record .credential_type , cred_value , gateway_auth_type
3974- )
3975- except Exception as e :
3976- logger .debug (f"Failed to check personal credentials for gateway { gateway_name } : { e } " )
3977-
3978- if user_credential_headers :
3979- headers = user_credential_headers
3980- else :
3981- headers = decode_auth (gateway_auth_value ) if gateway_auth_value else {}
3981+ # No per-user credentials and no OAuth — fall back to shared gateway auth
3982+ headers = decode_auth (gateway_auth_value ) if gateway_auth_value else {}
39823983
39833984 if request_headers :
39843985 headers = compute_passthrough_headers_cached (
@@ -5071,7 +5072,28 @@ async def invoke_tool(
50715072
50725073 # Handle OAuth authentication for the gateway (using local variables)
50735074 # NOTE: Use has_gateway instead of gateway to avoid accessing detached ORM object
5074- if has_gateway and gateway_auth_type == "oauth" and isinstance (gateway_oauth_config , dict ) and gateway_oauth_config :
5075+ # Per-user personal credentials always take priority over
5076+ # gateway-level OAuth tokens.
5077+ user_credential_headers = None
5078+ if has_gateway and app_user_email and gateway_id_str :
5079+ try :
5080+ from mcpgateway .services .credential_storage_service import CredentialStorageService # pylint: disable=import-outside-toplevel
5081+
5082+ with fresh_db_session () as cred_db :
5083+ cred_service = CredentialStorageService (cred_db )
5084+ cred_record = await cred_service .get_credential_record (gateway_id_str , app_user_email )
5085+ if cred_record :
5086+ cred_value = await cred_service .get_credential (gateway_id_str , app_user_email )
5087+ if cred_value :
5088+ user_credential_headers = CredentialStorageService .build_auth_headers (
5089+ cred_record .credential_type , cred_value , gateway_auth_type
5090+ )
5091+ except Exception as e :
5092+ logger .debug (f"Failed to check personal credentials for gateway { gateway_name } : { e } " )
5093+
5094+ if user_credential_headers :
5095+ headers = user_credential_headers
5096+ elif has_gateway and gateway_auth_type == "oauth" and isinstance (gateway_oauth_config , dict ) and gateway_oauth_config :
50755097 grant_type = gateway_oauth_config .get ("grant_type" , "client_credentials" )
50765098
50775099 if grant_type == "authorization_code" :
@@ -5118,28 +5140,8 @@ async def invoke_tool(
51185140 logger .error (f"Failed to obtain OAuth access token for gateway { gateway_name } : { e } " )
51195141 raise ToolInvocationError (f"OAuth authentication failed for gateway: { str (e )} " )
51205142 else :
5121- # Check for per-user personal credentials before falling back to shared gateway auth
5122- user_credential_headers = None
5123- if has_gateway and app_user_email and gateway_id_str :
5124- try :
5125- from mcpgateway .services .credential_storage_service import CredentialStorageService # pylint: disable=import-outside-toplevel
5126-
5127- with fresh_db_session () as cred_db :
5128- cred_service = CredentialStorageService (cred_db )
5129- cred_record = await cred_service .get_credential_record (gateway_id_str , app_user_email )
5130- if cred_record :
5131- cred_value = await cred_service .get_credential (gateway_id_str , app_user_email )
5132- if cred_value :
5133- user_credential_headers = CredentialStorageService .build_auth_headers (
5134- cred_record .credential_type , cred_value , gateway_auth_type
5135- )
5136- except Exception as e :
5137- logger .debug (f"Failed to check personal credentials for gateway { gateway_name } : { e } " )
5138-
5139- if user_credential_headers :
5140- headers = user_credential_headers
5141- else :
5142- headers = decode_auth (gateway_auth_value ) if gateway_auth_value else {}
5143+ # No per-user credentials and no OAuth — fall back to shared gateway auth
5144+ headers = decode_auth (gateway_auth_value ) if gateway_auth_value else {}
51435145
51445146 # Use cached passthrough headers (no DB query needed)
51455147 if request_headers :
0 commit comments