From 7c66f86f7f950a181f18a24f5efd9db6903b8bc2 Mon Sep 17 00:00:00 2001 From: shalper2 Date: Wed, 15 Apr 2026 10:51:09 -0500 Subject: [PATCH 1/6] added password grant fields --- http.json | 22 ++++++++++++++++------ http_connector.py | 18 +++++++++++++++++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/http.json b/http.json index 7438ea0..c5ea701 100644 --- a/http.json +++ b/http.json @@ -58,34 +58,44 @@ "order": 5, "description": "Password (for HTTP basic auth)" }, + "oauth_password": { + "data_type": "password", + "order": 6, + "description": "Optional: Password for OAuth password grants" + }, + "oauth_username": { + "data_type": "string", + "order": 7, + "description": "Optional: Username for OAuth password grants" + }, "oauth_token_url": { "data_type": "string", - "order": 6, + "order": 8, "description": "URL to fetch oauth token from" }, "placeholder": { "data_type": "ph", - "order": 7, + "order": 9, "description": "" }, "client_id": { "data_type": "string", - "order": 8, + "order": 10, "description": "Client ID (for OAuth)" }, "client_secret": { "data_type": "password", - "order": 9, + "order": 11, "description": "Client Secret (for OAuth)" }, "timeout": { "data_type": "numeric", - "order": 10, + "order": 12, "description": "Timeout for HTTP calls" }, "test_http_method": { "data_type": "string", - "order": 11, + "order": 13, "description": "HTTP Method for Test Connectivity", "default": "GET", "value_list": [ diff --git a/http_connector.py b/http_connector.py index a8a4ed2..0415630 100644 --- a/http_connector.py +++ b/http_connector.py @@ -64,6 +64,9 @@ def __init__(self): self._token = None self._username = None self._password = None + self._oauth_username = None + self._oauth_password = None + self._oauth_password_grant = False self._oauth_token_url = None self._client_id = None self._client_secret = None @@ -155,6 +158,12 @@ def initialize(self): self._password = config.get("password", "") self._test_http_method = config.get("test_http_method", "get").lower() + # if oauth password AND oauth username have been set we use the oauth password granttype + self._oauth_password = config.get("oauth_password") + self._oauth_username = config.get("oauth_username") + if self._oauth_password and self._oauth_username: + self._oauth_password_grant = True + self._oauth_token_url = config.get("oauth_token_url") if self._oauth_token_url: self._oauth_token_url = self._oauth_token_url.strip("/") @@ -501,7 +510,14 @@ def _generate_api_token(self, action_result, new_token=False): self.save_progress("Using old token") return self._access_token - payload = {"grant_type": "client_credentials"} + if self._oauth_password_grant: + payload = { + "grant_type": "password", + "username": self._oauth_username, + "password": self._oauth_password, + } + else: + payload = {"grant_type": "client_credentials"} self.save_progress("Fetching new token") # Querying endpoint to generate token From 83b49f208164acbff06d7d4c61b02d9c0240ddcb Mon Sep 17 00:00:00 2001 From: shalper2 Date: Wed, 15 Apr 2026 10:58:49 -0500 Subject: [PATCH 2/6] error handling --- README.md | 1 + http_connector.py | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 61d3383..16655cb 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ HTTPS) on your Phantom host(s) in order to function. 1. Basic Auth (username and password) 1. OAuth (oauth token url, client id and client secret) +1. OAuth Password grants 1. Provided Auth token (auth_token_name, auth_token) ### Configuration variables diff --git a/http_connector.py b/http_connector.py index 0415630..9658099 100644 --- a/http_connector.py +++ b/http_connector.py @@ -167,6 +167,7 @@ def initialize(self): self._oauth_token_url = config.get("oauth_token_url") if self._oauth_token_url: self._oauth_token_url = self._oauth_token_url.strip("/") + self._client_id = config.get("client_id") self._client_secret = config.get("client_secret") self._access_token = self._state.get(HTTP_JSON_ACCESS_TOKEN) @@ -510,15 +511,21 @@ def _generate_api_token(self, action_result, new_token=False): self.save_progress("Using old token") return self._access_token + payload = None if self._oauth_password_grant: payload = { "grant_type": "password", "username": self._oauth_username, "password": self._oauth_password, } - else: + + if self._oauth_token_url: payload = {"grant_type": "client_credentials"} + if not payload: + action_result.set_status(phantom.APP_ERROR, f"Improperly configured Oauth credentials") + return None + self.save_progress("Fetching new token") # Querying endpoint to generate token response = requests.post( From d3ee6b5b028b2bc9a7a00e2ed855d7a139d6dbcc Mon Sep 17 00:00:00 2001 From: shalper2 Date: Thu, 16 Apr 2026 12:45:35 -0500 Subject: [PATCH 3/6] updated readme --- README.md | 6 +++--- http.json | 12 ++++++------ http_connector.py | 7 +++---- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 16655cb..dfad234 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,9 @@ HTTPS) on your Phantom host(s) in order to function. **Authentication is carried out in following priority order** 1. Basic Auth (username and password) -1. OAuth (oauth token url, client id and client secret) -1. OAuth Password grants -1. Provided Auth token (auth_token_name, auth_token) +2. OAuth Password grants (username, password, oauth token url, client id and client secret) +3. OAuth (oauth token url, client id and client secret) +4. Provided Auth token (auth_token_name, auth_token) ### Configuration variables diff --git a/http.json b/http.json index c5ea701..293a40c 100644 --- a/http.json +++ b/http.json @@ -58,15 +58,15 @@ "order": 5, "description": "Password (for HTTP basic auth)" }, - "oauth_password": { - "data_type": "password", - "order": 6, - "description": "Optional: Password for OAuth password grants" - }, "oauth_username": { "data_type": "string", + "order": 6, + "description": "Username (for OAuth password grants)" + }, + "oauth_password": { + "data_type": "password", "order": 7, - "description": "Optional: Username for OAuth password grants" + "description": "Password (for OAuth password grants)" }, "oauth_token_url": { "data_type": "string", diff --git a/http_connector.py b/http_connector.py index 9658099..9a5ebd0 100644 --- a/http_connector.py +++ b/http_connector.py @@ -513,17 +513,16 @@ def _generate_api_token(self, action_result, new_token=False): payload = None if self._oauth_password_grant: + self.save_progress("Using password grant") payload = { "grant_type": "password", "username": self._oauth_username, "password": self._oauth_password, } - - if self._oauth_token_url: + else: + self.save_progress("Using client credentials") payload = {"grant_type": "client_credentials"} - if not payload: - action_result.set_status(phantom.APP_ERROR, f"Improperly configured Oauth credentials") return None self.save_progress("Fetching new token") From 92a05e1eb0d633576839026858973a81f34adb72 Mon Sep 17 00:00:00 2001 From: shalper2 Date: Thu, 16 Apr 2026 12:47:03 -0500 Subject: [PATCH 4/6] removed bad return --- http_connector.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/http_connector.py b/http_connector.py index 9a5ebd0..c285347 100644 --- a/http_connector.py +++ b/http_connector.py @@ -523,8 +523,6 @@ def _generate_api_token(self, action_result, new_token=False): self.save_progress("Using client credentials") payload = {"grant_type": "client_credentials"} - return None - self.save_progress("Fetching new token") # Querying endpoint to generate token response = requests.post( From 03af2e2276d517c1b4c9b3e5c97f13f9f337fa0e Mon Sep 17 00:00:00 2001 From: shalper2 Date: Thu, 16 Apr 2026 14:08:56 -0500 Subject: [PATCH 5/6] readme --- README.md | 4 ++++ http_connector.py | 38 +++++++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index dfad234..54693fa 100644 --- a/README.md +++ b/README.md @@ -32,12 +32,16 @@ VARIABLE | REQUIRED | TYPE | DESCRIPTION **auth_token** | optional | password | Value of authentication token | **username** | optional | string | Username (for HTTP basic auth) | **password** | optional | password | Password (for HTTP basic auth) | +**oauth_username** | optional | string | Username (for Oauth password grants) | +**oauth_password** | optional | password | Password (for Oauth password grants) | **oauth_token_url** | optional | string | URL to fetch oauth token from | **client_id** | optional | string | Client ID (for OAuth) | **client_secret** | optional | password | Client Secret (for OAuth) | **timeout** | optional | numeric | Timeout for HTTP calls | **test_http_method** | optional | string | HTTP Method for Test Connectivity | +Basic auth is configured using `username`/`password` fields. For Oauth password grants both the `oauth_username` and `oauth_password` fields must be configured. + ### Supported Actions [test connectivity](#action-test-connectivity) - Validate connection using the configured credentials
diff --git a/http_connector.py b/http_connector.py index c285347..9cc4745 100644 --- a/http_connector.py +++ b/http_connector.py @@ -161,8 +161,15 @@ def initialize(self): # if oauth password AND oauth username have been set we use the oauth password granttype self._oauth_password = config.get("oauth_password") self._oauth_username = config.get("oauth_username") - if self._oauth_password and self._oauth_username: - self._oauth_password_grant = True + + # make sure both are set together + if bool(self._oauth_password) != bool(self._oauth_username): + return self.set_status( + phantom.APP_ERROR, + "Both oauth_username and oauth_password must be provided together" + ) + + self._oauth_password_grant = bool(self._oauth_username and self._oauth_password) self._oauth_token_url = config.get("oauth_token_url") if self._oauth_token_url: @@ -419,7 +426,7 @@ def _make_http_call( if access_token and r.status_code == 401 and self.access_token_retry: self.save_progress(f"Got error: {r.status_code}") self._access_token = None - self._state.pop("access_token") + self._state.pop(HTTP_JSON_ACCESS_TOKEN, None) self.access_token_retry = False # make it to false to avoid getting access token after one time (prevents recursive loop) return self._make_http_call( action_result, @@ -511,7 +518,6 @@ def _generate_api_token(self, action_result, new_token=False): self.save_progress("Using old token") return self._access_token - payload = None if self._oauth_password_grant: self.save_progress("Using password grant") payload = { @@ -524,17 +530,27 @@ def _generate_api_token(self, action_result, new_token=False): payload = {"grant_type": "client_credentials"} self.save_progress("Fetching new token") + # Querying endpoint to generate token - response = requests.post( - self._oauth_token_url, - auth=HTTPBasicAuth(self._client_id, self._client_secret), # nosemgrep - data=payload, - timeout=DEFAULT_REQUEST_TIMEOUT, - ) + try: + response = requests.post( + self._oauth_token_url, + auth=HTTPBasicAuth(self._client_id, self._client_secret), # nosemgrep + data=payload, + timeout=DEFAULT_REQUEST_TIMEOUT, + ) + except Exception as e: + error_message = self._get_error_message_from_exception(e) + action_result.set_status( + phantom.APP_ERROR, + f"Error connecting to token endpoint {self._oauth_token_url}. Details: {error_message}", + ) + return None + if response.status_code not in [200, 201]: action_result.set_status( phantom.APP_ERROR, - f"Error fetching token from {self._oauth_token_url}. Server returned {response.status_code}", + f"Error fetching token from {self._oauth_token_url}. Server returned {response.status_code} with body {response.text}", ) return None From db261d1e3fe483bb48b2428894d38bcaff0e255d Mon Sep 17 00:00:00 2001 From: shalper2 Date: Fri, 29 May 2026 14:26:37 -0500 Subject: [PATCH 6/6] manual readme --- README.md | 3 --- manual_readme_content.md | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 54693fa..9078174 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,6 @@ HTTPS) on your Phantom host(s) in order to function. **Authentication is carried out in following priority order** 1. Basic Auth (username and password) -2. OAuth Password grants (username, password, oauth token url, client id and client secret) 3. OAuth (oauth token url, client id and client secret) 4. Provided Auth token (auth_token_name, auth_token) @@ -40,8 +39,6 @@ VARIABLE | REQUIRED | TYPE | DESCRIPTION **timeout** | optional | numeric | Timeout for HTTP calls | **test_http_method** | optional | string | HTTP Method for Test Connectivity | -Basic auth is configured using `username`/`password` fields. For Oauth password grants both the `oauth_username` and `oauth_password` fields must be configured. - ### Supported Actions [test connectivity](#action-test-connectivity) - Validate connection using the configured credentials
diff --git a/manual_readme_content.md b/manual_readme_content.md index c70b8a2..b5d7b1c 100644 --- a/manual_readme_content.md +++ b/manual_readme_content.md @@ -6,5 +6,8 @@ HTTPS) on your Phantom host(s) in order to function. **Authentication is carried out in following priority order** 1. Basic Auth (username and password) +1. OAuth Password grants (username, password, oauth token url, client id and client secret) 1. OAuth (oauth token url, client id and client secret) 1. Provided Auth token (auth_token_name, auth_token) + +Basic auth is configured using `username`/`password` fields. For Oauth password grants both the `oauth_username` and `oauth_password` fields must be configured.