From 6761ac6d8af5fbf2a22574da228c5d62ddbcdf94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Tue, 28 May 2024 14:33:02 +0200 Subject: [PATCH 01/11] Use PyJWT instead of python-jose --- intuitlib/utils.py | 11 ++++------- requirements.txt | 2 +- setup.py | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/intuitlib/utils.py b/intuitlib/utils.py index 68dddac..7080d98 100644 --- a/intuitlib/utils.py +++ b/intuitlib/utils.py @@ -20,11 +20,10 @@ from datetime import datetime import random import string -from jose import jwk import requests from requests.sessions import Session import six -from requests_oauthlib import OAuth1 +from jwt import PyJWKSet from intuitlib.enums import Scopes @@ -165,9 +164,8 @@ def validate_id_token(id_token, client_id, intuit_issuer, jwk_uri): return False message = id_token_parts[0] + '.' + id_token_parts[1] - keys_dict = get_jwk(id_token_header['kid'], jwk_uri) + public_key = get_jwk(id_token_header['kid'], jwk_uri) - public_key = jwk.construct(keys_dict) is_signature_valid = public_key.verify(message.encode('utf-8'), id_token_signature) return is_signature_valid @@ -178,15 +176,14 @@ def get_jwk(kid, jwk_uri): :param jwk_uri: JWK URI :raises HTTPError: if response status != 200 - :return: dict containing keys + :return: Algorithm with the key loaded. """ response = requests.get(jwk_uri) if response.status_code != 200: raise AuthClientError(response) data = response.json() - keys = next(key for key in data["keys"] if key['kid'] == kid) - return keys + return PyJWKSet.from_dict(data)[kid] def _correct_padding(val): """Correct padding for JWT diff --git a/requirements.txt b/requirements.txt index e0f41ba..a5c2d2c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -python_jose>=2.0.2 requests>=2.13.0 mock>=2.0.0 requests_oauthlib>=1.0.0 @@ -8,3 +7,4 @@ pytest>=3.8.0 pytest-cov==2.5.0 six>=1.10.0 enum-compat +pyjwt diff --git a/setup.py b/setup.py index 8d030be..19b0451 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ packages=find_packages(exclude=('tests*',)), namespace_packages=('intuitlib',), install_requires=[ - 'python_jose>=2.0.2', + 'pyjwt', 'requests>=2.13.0', 'requests_oauthlib>=1.0.0', 'six>=1.10.0', From 7f46c32b118047a01a7ad9bac43553295e9d2a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Tue, 9 Jul 2024 17:50:20 +0200 Subject: [PATCH 02/11] Add PyJWT minimum supported version --- requirements.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index a5c2d2c..809712d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,4 @@ pytest>=3.8.0 pytest-cov==2.5.0 six>=1.10.0 enum-compat -pyjwt +pyjwt>=2.0.0 diff --git a/setup.py b/setup.py index 19b0451..9595906 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ packages=find_packages(exclude=('tests*',)), namespace_packages=('intuitlib',), install_requires=[ - 'pyjwt', + 'pyjwt>=2.0.0', 'requests>=2.13.0', 'requests_oauthlib>=1.0.0', 'six>=1.10.0', From 703c3e8b4c723f29853e53df64bde72469ec145f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Tue, 9 Jul 2024 19:26:21 +0200 Subject: [PATCH 03/11] Add the Cryptography related algorithms --- requirements.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 809712d..1e1db9d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,4 @@ pytest>=3.8.0 pytest-cov==2.5.0 six>=1.10.0 enum-compat -pyjwt>=2.0.0 +pyjwt[crypto]>=2.0.0 diff --git a/setup.py b/setup.py index 9595906..b40522c 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ packages=find_packages(exclude=('tests*',)), namespace_packages=('intuitlib',), install_requires=[ - 'pyjwt>=2.0.0', + 'pyjwt[crypto]>=2.0.0', 'requests>=2.13.0', 'requests_oauthlib>=1.0.0', 'six>=1.10.0', From 96e4f37df79921964e83bbeaa55a6553e8e1ab33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Sun, 21 Jul 2024 09:20:51 +0200 Subject: [PATCH 04/11] Update intuitlib/utils.py --- intuitlib/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intuitlib/utils.py b/intuitlib/utils.py index 7080d98..af35143 100644 --- a/intuitlib/utils.py +++ b/intuitlib/utils.py @@ -164,7 +164,7 @@ def validate_id_token(id_token, client_id, intuit_issuer, jwk_uri): return False message = id_token_parts[0] + '.' + id_token_parts[1] - public_key = get_jwk(id_token_header['kid'], jwk_uri) + public_key = get_jwk(id_token_header['kid'], jwk_uri).key is_signature_valid = public_key.verify(message.encode('utf-8'), id_token_signature) return is_signature_valid From b67444fa0a341d42d42a9d1bf951289a6535a1f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Sun, 28 Jul 2024 19:25:23 +0200 Subject: [PATCH 05/11] Use jwt.decode public API --- intuitlib/utils.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/intuitlib/utils.py b/intuitlib/utils.py index af35143..04e4c43 100644 --- a/intuitlib/utils.py +++ b/intuitlib/utils.py @@ -16,19 +16,19 @@ """ import json -from base64 import b64encode, b64decode, urlsafe_b64decode -from datetime import datetime import random -import string import requests -from requests.sessions import Session import six -from jwt import PyJWKSet - +import string +from base64 import b64encode, b64decode, urlsafe_b64decode +from datetime import datetime +from jwt import PyJWKSet, PyJWTError +from requests.sessions import Session +from intuitlib.config import DISCOVERY_URL, ACCEPT_HEADER from intuitlib.enums import Scopes from intuitlib.exceptions import AuthClientError -from intuitlib.config import DISCOVERY_URL, ACCEPT_HEADER + def get_discovery_doc(environment, session=None): """Gets discovery doc based on environment specified. @@ -165,9 +165,11 @@ def validate_id_token(id_token, client_id, intuit_issuer, jwk_uri): message = id_token_parts[0] + '.' + id_token_parts[1] public_key = get_jwk(id_token_header['kid'], jwk_uri).key - - is_signature_valid = public_key.verify(message.encode('utf-8'), id_token_signature) - return is_signature_valid + try: + jwt.decode(id_token, public_key, audience=client_id, algorithms=['RS256']) + return True + except PyJWTError: + return False def get_jwk(kid, jwk_uri): """Get JWK for public key information From 9cb5d8728dcab9184f3134b10fe8d17510a62457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Tue, 30 Jul 2024 07:00:55 +0200 Subject: [PATCH 06/11] Fix QA returns --- intuitlib/utils.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/intuitlib/utils.py b/intuitlib/utils.py index 04e4c43..4a9e34a 100644 --- a/intuitlib/utils.py +++ b/intuitlib/utils.py @@ -16,13 +16,13 @@ """ import json +import jwt import random import requests import six import string from base64 import b64encode, b64decode, urlsafe_b64decode from datetime import datetime -from jwt import PyJWKSet, PyJWTError from requests.sessions import Session from intuitlib.config import DISCOVERY_URL, ACCEPT_HEADER @@ -152,7 +152,6 @@ def validate_id_token(id_token, client_id, intuit_issuer, jwk_uri): id_token_header = json.loads(b64decode(_correct_padding(id_token_parts[0])).decode('ascii')) id_token_payload = json.loads(b64decode(_correct_padding(id_token_parts[1])).decode('ascii')) - id_token_signature = urlsafe_b64decode(((_correct_padding(id_token_parts[2])).encode('ascii'))) if id_token_payload['iss'] != intuit_issuer: return False @@ -163,12 +162,11 @@ def validate_id_token(id_token, client_id, intuit_issuer, jwk_uri): if id_token_payload['exp'] < current_time: return False - message = id_token_parts[0] + '.' + id_token_parts[1] public_key = get_jwk(id_token_header['kid'], jwk_uri).key try: jwt.decode(id_token, public_key, audience=client_id, algorithms=['RS256']) return True - except PyJWTError: + except jwt.PyJWTError: return False def get_jwk(kid, jwk_uri): @@ -185,7 +183,7 @@ def get_jwk(kid, jwk_uri): if response.status_code != 200: raise AuthClientError(response) data = response.json() - return PyJWKSet.from_dict(data)[kid] + return jwt.PyJWKSet.from_dict(data)[kid] def _correct_padding(val): """Correct padding for JWT From bec9ce4d5b9c72df66b387785c84904e84fa1724 Mon Sep 17 00:00:00 2001 From: Robert Mings Date: Wed, 31 Jul 2024 16:04:24 -0700 Subject: [PATCH 07/11] chore: update readme, docs + general cleanup --- README.rst | 41 +++++++++++++++++++++-------------------- docs/index.rst | 31 ++++++++++++++++++------------- intuitlib/utils.py | 2 +- intuitlib/version.py | 2 +- views/SDK.png | Bin 15593 -> 0 bytes 5 files changed, 41 insertions(+), 35 deletions(-) delete mode 100644 views/SDK.png diff --git a/README.rst b/README.rst index 6d1b879..e98f047 100644 --- a/README.rst +++ b/README.rst @@ -1,13 +1,7 @@ -.. image:: views/SDK.png - :target: https://help.developer.intuit.com/s/samplefeedback?cid=1110&repoName=oauth-pythonclient - -Intuit's OAuth2 and OpenID Python Client +Intuit's OAuth2 and OpenID Connect Python Client ======================================== -|build| |coverage| |docs| - -.. |build| image:: https://travis-ci.com/intuit/oauth-pythonclient.svg?branch=master - :target: https://travis-ci.com/intuit/oauth-pythonclient +|coverage| |docs| .. |coverage| image:: https://coveralls.io/repos/github/intuit/oauth-pythonclient/badge.svg?branch=master :target: https://coveralls.io/github/intuit/oauth-pythonclient?branch=master @@ -16,14 +10,21 @@ Intuit's OAuth2 and OpenID Python Client :target: https://oauth-pythonclient.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status -This client library is meant to work with Intuit's OAuth and OpenID implementation. The `AuthClient` object response can be used for User Info API, Accounting API and Payments API. This library supports: - -- Generating Authorization URL -- Getting OAuth2 Bearer Token -- Getting User Info -- Validating OpenID token -- Refreshing OAuth2 Token -- Revoking OAuth2 Token +The official Python client library for working with Intuit APIs. +The `AuthClient` object response can be used for the +`Intuit UserInfo API `_, +`QuickBooks Accounting API `_, +and `QuickBooks Payments API `_. + +This library supports: + +- Raising authorization requests +- Requesting OAuth2 bearer (access) tokens +- Refreshing OAuth2 tokens +- Revoking OAuth2 tokens +- Validating ID tokens +- Fetching profile attributes from UserInfo +- Various utility methods - Migrating tokens from OAuth1.0 to OAuth2 Install @@ -36,19 +37,19 @@ Using `pip `_: :: Documentation ------------- -Usage and Reference Documentation can be found at `oauth-pythonclient.readthedocs.io `_ +Usage and reference documentation can be found at `oauth-pythonclient.readthedocs.io `_. Sample App ---------- -Sample app for this library can be found at `IntuitDeveloper GitHub Org `_ +A sample app for this library can be found on the `IntuitDeveloper GitHub Org `_. Issues and Contributions ------------------------ -Please open an `issue `_ on GitHub if you have a problem, suggestion, or other comment. +Please open an `issue `_ on GitHub if you have anything to report, a suggestion, or comment. -Pull requests are welcome and encouraged! Any contributions should include new or updated unit tests as necessary to maintain thorough test coverage. +Pull requests are welcomed and encouraged! Any contributions should include new or updated unit tests as necessary to maintain thorough test coverage. License ------- diff --git a/docs/index.rst b/docs/index.rst index 6032118..d07c0aa 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,29 +3,34 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Intuit's OAuth2 and OpenID Client +Intuit's OAuth2 and OpenID Connect Client ================================= -`View on GitHub `_ - -This client library is meant to work with Intuit's OAuth and OpenID implementation. The `bearer_token` response can be used for User Info API, Accounting API and Payments API. It supports: - -- Generating Authorization URL -- Getting OAuth2 Bearer Token -- Getting User Info -- Validating OpenID token -- Refreshing OAuth2 Token -- Revoking OAuth2 Token +The official Python client library for working with Intuit APIs. +The `AuthClient` object response can be used for the +`Intuit UserInfo API `_, +`QuickBooks Accounting API `_, +and `QuickBooks Payments API `_. + +This library supports: + +- Raising authorization requests +- Requesting OAuth2 bearer (access) tokens +- Refreshing OAuth2 tokens +- Revoking OAuth2 tokens +- Validating ID tokens +- Fetching profile attributes from UserInfo +- Various utility methods - Migrating tokens from OAuth1.0 to OAuth2 +`View this library on GitHub `_ + Install Client -------------- This library can be installed using `pip `_:: $ pip install intuit-oauth -View it on GitHub `here `_ - Docs ---- diff --git a/intuitlib/utils.py b/intuitlib/utils.py index 4a9e34a..c1fd832 100644 --- a/intuitlib/utils.py +++ b/intuitlib/utils.py @@ -21,7 +21,7 @@ import requests import six import string -from base64 import b64encode, b64decode, urlsafe_b64decode +from base64 import b64encode, b64decode from datetime import datetime from requests.sessions import Session diff --git a/intuitlib/version.py b/intuitlib/version.py index 91ab2ed..f17380e 100644 --- a/intuitlib/version.py +++ b/intuitlib/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = '1.2.5' +__version__ = '1.2.6' diff --git a/views/SDK.png b/views/SDK.png deleted file mode 100644 index 1e4fdb2ebd7b7f54d3fcf59c6b899bb477e744d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15593 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%0Ai$Se3CR2l5p`f8S+eM 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 Date: Wed, 31 Jul 2024 16:47:46 -0700 Subject: [PATCH 08/11] chore: description cleanup --- README.rst | 4 ++-- docs/index.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index e98f047..c264e01 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ Intuit's OAuth2 and OpenID Connect Python Client -======================================== +================================================= |coverage| |docs| @@ -54,4 +54,4 @@ Pull requests are welcomed and encouraged! Any contributions should include new License ------- -This library is provided under Apache 2.0 which is found `here `__ +This library is provided under Apache 2.0 which is found `here `_ diff --git a/docs/index.rst b/docs/index.rst index d07c0aa..ff2b41e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -4,7 +4,7 @@ contain the root `toctree` directive. Intuit's OAuth2 and OpenID Connect Client -================================= +========================================== The official Python client library for working with Intuit APIs. The `AuthClient` object response can be used for the From 8b2b460df3a6fe54eb5a85e53d3361aa6c7cbd7b Mon Sep 17 00:00:00 2001 From: Soumiya M <153138345+Soumiya-mohan@users.noreply.github.com> Date: Thu, 8 May 2025 14:56:57 -0700 Subject: [PATCH 09/11] Update enums.py update scope enum for projects, custom fields and time-tracking --- intuitlib/enums.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/intuitlib/enums.py b/intuitlib/enums.py index 15aa88b..9d94ad1 100644 --- a/intuitlib/enums.py +++ b/intuitlib/enums.py @@ -28,13 +28,18 @@ class Scopes(Enum): OPENID = 'openid' ACCOUNTING = 'com.intuit.quickbooks.accounting' PAYMENT = 'com.intuit.quickbooks.payment' - + # for whitelisted Beta apps only PAYROLL = 'com.intuit.quickbooks.payroll' PAYROLL_TIMETRACKING = 'com.intuit.quickbooks.payroll.timetracking' PAYROLL_BENEFITS = 'com.intuit.quickbooks.payroll.benefits' PAYSLIP_READ = 'com.intuit.quickbooks.payroll.payslip.read' + PROJECT MANAGEMENT = 'project-management.project' + CUSTOM_FIELDS_READ = 'app-foundations.custom-field-definitions.read' + CUSTOM_FIELDS = 'app-foundations.custom-field-definitions' + EMPLOYEE_COMPENSATION = 'payroll.compensation.read' + # For migrated apps only # To not see consent page they should pass the following scopes - openid intuit_name email - INTUIT_NAME = 'intuit_name' \ No newline at end of file + INTUIT_NAME = 'intuit_name' From 5f6e3bf5c33fa9401833b624813ce79a03475691 Mon Sep 17 00:00:00 2001 From: Soumiya M <153138345+Soumiya-mohan@users.noreply.github.com> Date: Thu, 8 May 2025 15:01:10 -0700 Subject: [PATCH 10/11] Update enums.py update scope enums for projects, custom fields and time tracking --- intuitlib/enums.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intuitlib/enums.py b/intuitlib/enums.py index 9d94ad1..19f3ec3 100644 --- a/intuitlib/enums.py +++ b/intuitlib/enums.py @@ -34,7 +34,7 @@ class Scopes(Enum): PAYROLL_TIMETRACKING = 'com.intuit.quickbooks.payroll.timetracking' PAYROLL_BENEFITS = 'com.intuit.quickbooks.payroll.benefits' PAYSLIP_READ = 'com.intuit.quickbooks.payroll.payslip.read' - PROJECT MANAGEMENT = 'project-management.project' + PROJECT_MANAGEMENT = 'project-management.project' CUSTOM_FIELDS_READ = 'app-foundations.custom-field-definitions.read' CUSTOM_FIELDS = 'app-foundations.custom-field-definitions' EMPLOYEE_COMPENSATION = 'payroll.compensation.read' From 6cb7c291a807bda5b5b14991c645fcdad0171fd3 Mon Sep 17 00:00:00 2001 From: Soumiya M <153138345+Soumiya-mohan@users.noreply.github.com> Date: Thu, 15 May 2025 13:09:32 -0700 Subject: [PATCH 11/11] Update enums.py --- intuitlib/enums.py | 1 + 1 file changed, 1 insertion(+) diff --git a/intuitlib/enums.py b/intuitlib/enums.py index 19f3ec3..8b71a2e 100644 --- a/intuitlib/enums.py +++ b/intuitlib/enums.py @@ -38,6 +38,7 @@ class Scopes(Enum): CUSTOM_FIELDS_READ = 'app-foundations.custom-field-definitions.read' CUSTOM_FIELDS = 'app-foundations.custom-field-definitions' EMPLOYEE_COMPENSATION = 'payroll.compensation.read' + TAX = 'indirect-tax.tax-calculation.quickbooks' # For migrated apps only