diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 86e3b87..5708967 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] - python: [ '3.8', '3.9' ] + python: [ '3.8', '3.9', '3.10' ] name: Python ${{ matrix.python }} steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a52771..36819d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Release History +## 3.1.0 +* Add support for Client Credentials Grant + ## 3.0.4 * Add GraphQL support diff --git a/example/myapp.py b/example/myapp.py index 5e2c846..3b7cd96 100644 --- a/example/myapp.py +++ b/example/myapp.py @@ -34,11 +34,15 @@ def get_desktop_client(): # token = {'access_token': 'xxxxxxxxxxxxxxxxxx', 'expires_at': 1590479276.547947, 'expires_in': '86400', 'refresh_token': 'xxxxxxxxxxxxxxxxxxxxxxxx', 'token_type': 'Bearer'} # config = upwork.Config({'client_id': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'client_secret': 'xxxxxxxxxxxxx', 'token': token}) + # For Client Credentials Grant the following config must be used, no other parameters are needed + # config = upwork.Config({'client_id': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'client_secret': 'xxxxxxxxxxxxx', 'grant_type': 'client_credentials'}) + client = upwork.Client(config) try: config.token except AttributeError: + # remove client.get_authorization_url and authz_code input in case Client Credentials Grant is used authorization_url, state = client.get_authorization_url() # cover "state" flow if needed authz_code = input( @@ -48,6 +52,7 @@ def get_desktop_client(): print("Retrieving access and refresh tokens.... ") token = client.get_access_token(authz_code) + # token = client.get_access_token() # for Client Credentials Grant # WARNING: the access token will be refreshed automatically for you # in case it's expired, i.e. expires_at < time(). Make sure you replace the # old token accordingly in your security storage. Call client.get_actual_config diff --git a/noxfile.py b/noxfile.py index 66bdf2b..0e34513 100644 --- a/noxfile.py +++ b/noxfile.py @@ -3,7 +3,7 @@ nox.options.sessions = ["tests", "lint", "build"] -python = ["3.9"] +python = ["3.10"] lint_dependencies = [ @@ -35,7 +35,7 @@ def cover(session): session.run("coverage", "erase") -@nox.session(python="3.9") +@nox.session(python="3.10") def lint(session): session.install(*lint_dependencies) files = ["tests"] + [str(p) for p in Path(".").glob("*.py")] @@ -49,7 +49,7 @@ def lint(session): session.run("check-manifest") -@nox.session(python="3.9") +@nox.session(python="3.10") def build(session): session.install("setuptools") session.install("wheel") @@ -58,7 +58,7 @@ def build(session): session.run("python", "setup.py", "--quiet", "sdist", "bdist_wheel") -@nox.session(python="3.9") +@nox.session(python="3.10") def publish(session): build(session) print("REMINDER: Has the changelog been updated?") diff --git a/setup.py b/setup.py index c7b2c77..c682e36 100644 --- a/setup.py +++ b/setup.py @@ -31,6 +31,6 @@ packages=find_packages(), setup_requires=[], url="https://github.com/upwork/python-upwork-oauth2", - version="3.0.4", + version="3.1.0", zip_safe=False, ) diff --git a/upwork/__init__.py b/upwork/__init__.py index 9d2fa81..151f3d5 100644 --- a/upwork/__init__.py +++ b/upwork/__init__.py @@ -6,6 +6,6 @@ __author__ = """Maksym Novozhylov""" __email__ = "mnovozhilov@upwork.com" -__version__ = "3.0.4" +__version__ = "3.1.0" __all__ = ("Config", "Client", "routers") diff --git a/upwork/client.py b/upwork/client.py index 122260b..68d9c39 100644 --- a/upwork/client.py +++ b/upwork/client.py @@ -12,6 +12,7 @@ # License:: See LICENSE.txt and TOS - https://developers.upwork.com/api-tos.html from . import upwork +from oauthlib.oauth2 import BackendApplicationClient from requests_oauthlib import OAuth2Session # type: ignore from urllib.parse import parse_qsl, urlencode @@ -48,10 +49,16 @@ def __init__(self, config): token_updater=self.refresh_config_from_access_token, ) except AttributeError as e: - # start from authorization step - self.__oauth = OAuth2Session( - self.config.client_id, redirect_uri=self.config.redirect_uri - ) + if self.config.grant_type == "client_credentials": + client = BackendApplicationClient(client_id=self.config.client_id) + self.__oauth = OAuth2Session( + client=client + ) + else: + # start from authorization step + self.__oauth = OAuth2Session( + self.config.client_id, redirect_uri=self.config.redirect_uri + ) def get_authorization_url(self): """Get authorization URL @@ -63,7 +70,7 @@ def get_authorization_url(self): "{0}{1}".format(upwork.BASE_HOST, self.__uri_auth) ) - def get_access_token(self, authorization_response): + def get_access_token(self, authorization_response=None): """Finish auth process and get access token :param authorization_response: diff --git a/upwork/config.py b/upwork/config.py index 0f01d0d..d57f816 100644 --- a/upwork/config.py +++ b/upwork/config.py @@ -21,6 +21,11 @@ def __init__(self, config): config["client_secret"], ) + if "grant_type" in config: + self.grant_type = config["grant_type"] + else: + self.grant_type = None # Authorization Code Grant flow is used by default + if "redirect_uri" in config: self.redirect_uri = config["redirect_uri"]