From b1fbd71078e5e34f8a853bc2168c056eb92f23fe Mon Sep 17 00:00:00 2001 From: "nishant.katkade" Date: Mon, 2 Feb 2026 13:58:09 +0530 Subject: [PATCH 1/2] feat/added oauth support for dashboard apis --- juspay_dashboard_mcp/api/utils.py | 139 +++++++++++++++++++----------- juspay_dashboard_mcp/config.py | 9 +- 2 files changed, 99 insertions(+), 49 deletions(-) diff --git a/juspay_dashboard_mcp/api/utils.py b/juspay_dashboard_mcp/api/utils.py index 2f63aa4..3fd4d51 100644 --- a/juspay_dashboard_mcp/api/utils.py +++ b/juspay_dashboard_mcp/api/utils.py @@ -84,8 +84,6 @@ async def get_juspay_host_from_api(token: str = None, headers: dict = None, meta Returns the Juspay host URL based on token validation. Calls the validate API and uses the 'validHost' field from the response. """ - validate_url = f"{JUSPAY_BASE_URL}/api/ec/v1/validate/token" - # Get token from header credentials context first, then fallback to other sources juspay_creds = get_juspay_credentials() token_to_use = token @@ -100,28 +98,51 @@ async def get_juspay_host_from_api(token: str = None, headers: dict = None, meta if not token_to_use: raise Exception("Juspay token not provided.") + + token_response = (meta_info or {}).get("token_response") or {} + auth_type = token_response.get("auth_type") + try: - json_payload = {"token": token_to_use} - juspay_creds = get_juspay_credentials() - request_api_headers = get_common_headers(json_payload, meta_info, juspay_creds) - if headers: # headers from function signature - request_api_headers.update(headers) - - async with httpx.AsyncClient(timeout=30.0) as client: - resp = await client.post( - validate_url, - headers=request_api_headers, - json=json_payload - ) - resp.raise_for_status() - data = resp.json() - valid_host = data.get("validHost") - if not valid_host: - raise Exception("validHost not found in Juspay token validation response.") - if not valid_host.startswith("http"): - valid_host = f"https://{valid_host}" - logger.info(f"Using valid host: {valid_host}") - return valid_host + if auth_type == "oauth": + resource_param = '{%22COMMON%22%20%3A%20%22R%22}' + url = f"{JUSPAY_BASE_URL}/ec/v2/authorize?resource={resource_param}" + oauth_headers = { + "Authorization": token_to_use, + } + + logger.info(f"OAuth authorization - Request URL: GET {url}") + logger.info(f"OAuth authorization - Request Headers: {oauth_headers}") + + async with httpx.AsyncClient(timeout=10.0) as client: + resp = await client.get(url, headers=oauth_headers) + resp.raise_for_status() + # Authorization successful, return JUSPAY_BASE_URL for OAuth + logger.info(f"OAuth auth_type detected, returning {JUSPAY_BASE_URL}") + return JUSPAY_BASE_URL + else: + # For non-OAuth, use regular token validation endpoint + validate_url = f"{JUSPAY_BASE_URL}/api/ec/v1/validate/token" + json_payload = {"token": token_to_use} + juspay_creds = get_juspay_credentials() + request_api_headers = get_common_headers(json_payload, meta_info, juspay_creds) + if headers: # headers from function signature + request_api_headers.update(headers) + + async with httpx.AsyncClient(timeout=30.0) as client: + resp = await client.post( + validate_url, + headers=request_api_headers, + json=json_payload + ) + resp.raise_for_status() + data = resp.json() + valid_host = data.get("validHost") + if not valid_host: + raise Exception("validHost not found in Juspay token validation response.") + if not valid_host.startswith("http"): + valid_host = f"https://{valid_host}" + logger.info(f"Using valid host: {valid_host}") + return valid_host except Exception as e: logger.error(f"Token validation failed: {e}") raise @@ -136,8 +157,6 @@ async def get_admin_host(token: str = None, headers: dict = None ,meta_info: dic - valid_host: The host URL string - isadmin: True if context is "JUSPAY", False otherwise """ - validate_url = f"{JUSPAY_BASE_URL}/api/ec/v1/validate/token" - # Get token from header credentials context first, then fallback to other sources juspay_creds = get_juspay_credentials() token_to_use = token @@ -151,31 +170,55 @@ async def get_admin_host(token: str = None, headers: dict = None ,meta_info: dic if not token_to_use: raise Exception("Juspay token not provided.") + + token_response = (meta_info or {}).get("token_response") or {} + auth_type = token_response.get("auth_type") + try: - json_payload = {"token": token_to_use} - # Pass juspay_creds to get_common_headers to avoid environment variable verification - juspay_creds = get_juspay_credentials() - request_api_headers = get_common_headers(json_payload, meta_info, juspay_creds) - - async with httpx.AsyncClient(timeout=30.0) as client: - resp = await client.post( - validate_url, - headers=request_api_headers, - json=json_payload - ) - resp.raise_for_status() - data = resp.json() - context = data.get("context") - # Check if context is JUSPAY - isadmin = context == "JUSPAY" - - valid_host = data.get("validHost") - if not valid_host: - raise Exception("validHost not found in Juspay token validation response.") - if not valid_host.startswith("http"): - valid_host = f"https://{valid_host}" + if auth_type == "oauth": + resource_param = '{%22COMMON%22%20%3A%20%22R%22}' + url = f"{JUSPAY_BASE_URL}/ec/v2/authorize?resource={resource_param}" + oauth_headers = { + "Authorization": token_to_use, + } + + logger.info(f"OAuth authorization - Request URL: GET {url}") + logger.info(f"OAuth authorization - Request Headers: {oauth_headers}") + + async with httpx.AsyncClient(timeout=10.0) as client: + resp = await client.get(url, headers=oauth_headers) + resp.raise_for_status() + # Authorization successful, return JUSPAY_BASE_URL for OAuth + logger.info(f"OAuth auth_type detected, returning {JUSPAY_BASE_URL}") + # For OAuth, we assume admin context (you may want to adjust this based on your requirements) + return JUSPAY_BASE_URL, True + else: + # For non-OAuth, use regular token validation endpoint + validate_url = f"{JUSPAY_BASE_URL}/api/ec/v1/validate/token" + json_payload = {"token": token_to_use} + # Pass juspay_creds to get_common_headers to avoid environment variable verification + juspay_creds = get_juspay_credentials() + request_api_headers = get_common_headers(json_payload, meta_info, juspay_creds) - return valid_host, isadmin + async with httpx.AsyncClient(timeout=30.0) as client: + resp = await client.post( + validate_url, + headers=request_api_headers, + json=json_payload + ) + resp.raise_for_status() + data = resp.json() + context = data.get("context") + # Check if context is JUSPAY + isadmin = context == "JUSPAY" + + valid_host = data.get("validHost") + if not valid_host: + raise Exception("validHost not found in Juspay token validation response.") + if not valid_host.startswith("http"): + valid_host = f"https://{valid_host}" + + return valid_host, isadmin except Exception as e: logger.error(f"Token validation failed: {e}") raise diff --git a/juspay_dashboard_mcp/config.py b/juspay_dashboard_mcp/config.py index 45418bc..16812f5 100644 --- a/juspay_dashboard_mcp/config.py +++ b/juspay_dashboard_mcp/config.py @@ -65,13 +65,20 @@ def get_common_headers(payload: dict, meta_info: dict = None, juspay_creds: dict else: token = JUSPAY_WEB_LOGIN_TOKEN + token_response = (meta_info or {}).get("token_response") or {} + auth_type = token_response.get("auth_type") + default_headers = { "Content-Type": "application/json", "accept": "*/*", "x-request-id": f"mcp-tool-{os.urandom(6).hex()}", - "x-web-logintoken": f"{token}", } + if auth_type == "oauth": + default_headers["Authorization"] = token + else: + default_headers["x-web-logintoken"] = f"{token}" + if payload.get("tenant_id"): default_headers["x-tenant-id"] = payload.pop("tenant_id") From b7af0c2da6bacc41e714ec1ffdc904f39f51b139 Mon Sep 17 00:00:00 2001 From: "nishant.katkade" Date: Mon, 2 Feb 2026 14:02:38 +0530 Subject: [PATCH 2/2] feat/removed the header logger --- juspay_dashboard_mcp/api/utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/juspay_dashboard_mcp/api/utils.py b/juspay_dashboard_mcp/api/utils.py index 3fd4d51..cd43776 100644 --- a/juspay_dashboard_mcp/api/utils.py +++ b/juspay_dashboard_mcp/api/utils.py @@ -111,7 +111,6 @@ async def get_juspay_host_from_api(token: str = None, headers: dict = None, meta } logger.info(f"OAuth authorization - Request URL: GET {url}") - logger.info(f"OAuth authorization - Request Headers: {oauth_headers}") async with httpx.AsyncClient(timeout=10.0) as client: resp = await client.get(url, headers=oauth_headers) @@ -183,7 +182,6 @@ async def get_admin_host(token: str = None, headers: dict = None ,meta_info: dic } logger.info(f"OAuth authorization - Request URL: GET {url}") - logger.info(f"OAuth authorization - Request Headers: {oauth_headers}") async with httpx.AsyncClient(timeout=10.0) as client: resp = await client.get(url, headers=oauth_headers)