Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions docs/user-guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,22 @@ Get authorization url by specifying list of `intuitlib.enums.Scopes` ::
After user connects to the app, the callback URL has params for `state`, `auth_code` and `realm_id` (`realm_id` for Accounting and Payments scopes only)

Step 3: Get Tokens and Expiry details
++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++

The `auth_code` from URL params from Step 2 is used to get bearer tokens. Optionally, `realm_id` is passed to set this property for `auth_client` object. ::

auth_client.get_bearer_token(auth_code, realm_id=realm_id)

After successful response, `access_token`, `refresh_token`, etc properties of `auth_client` object are set.

Refresh Token Hard Expiry
+++++++++++++++++++++++++

To opt in Refresh Token Hard Expiry, call `set_include_refresh_token_hard_expires_in` on the client.

auth_client.set_include_refresh_token_hard_expires_in(True)

After successful response, `access_token`, `refresh_token`, `expires_in`, `x_refresh_token_expires_in`, etc properties of `auth_client` object are set.


Step 4 (OAuth): Sample API Call
+++++++++++++++++++++++++++++++

Expand Down Expand Up @@ -71,6 +79,10 @@ Or by passing the `refresh_token` as a parameter: ::

auth_client.refresh(refresh_token='EnterRefreshTokenHere')

To opt in Hard Expiry during refresh calls, call `set_include_refresh_token_hard_expires_in` on the client.

auth_client.set_include_refresh_token_hard_expires_in(True)

Revoke Tokens
-------------

Expand Down Expand Up @@ -110,7 +122,3 @@ In case of HTTP Errors, the client raises `intuitlib.exceptions.AuthClientError`
print(e.status_code)
print(e.content)
print(e.intuit_tid)




46 changes: 46 additions & 0 deletions intuitlib/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
except (ModuleNotFoundError, ImportError):
from future.moves.urllib.parse import urlencode

from intuitlib.config import INCLUDE_REFRESH_TOKEN_HARD_EXPIRES_IN_HEADER
from intuitlib.utils import (
get_discovery_doc,
generate_token,
Expand Down Expand Up @@ -69,8 +70,47 @@ def __init__(self, client_id, client_secret, redirect_uri, environment, state_to
self.expires_in = None
self.refresh_token = refresh_token
self.x_refresh_token_expires_in = None
self.x_refresh_token_hard_expires_in = None
self.id_token = id_token

# When True, token-endpoint requests include the x-include-refresh-token-hard-expires-in header so the response carries
# x_refresh_token_hard_expires_in (absolute refresh-token lifespan).
self._include_refresh_token_hard_expires_in = False

def set_include_refresh_token_hard_expires_in(self, enabled=False):
"""Opt in to receive refresh token hard expiry on token-endpoint responses.

When enabled, every subsequent get_bearer_token/refresh call sends the
`x-include-refresh-token-hard-expires-in` header. The parsed value is
available on `auth_client.x_refresh_token_hard_expires_in`."""

if isinstance(enabled, bool):
self._include_refresh_token_hard_expires_in = enabled
elif isinstance(enabled, str):
normalized = enabled.strip().lower()
if normalized == 'true':
self._include_refresh_token_hard_expires_in = True
else:
self._include_refresh_token_hard_expires_in = False
else:
self._include_refresh_token_hard_expires_in = False
return self

def get_include_refresh_token_hard_expires_in(self):
"""Whether the refresh token hard expiry header is currently being sent.
:return: bool
"""
return self._include_refresh_token_hard_expires_in

def _apply_refresh_token_hard_expires_in_header(self, headers):
"""Conditionally add the hard-expires opt-in header.
Uses the instance flag set via set_include_refresh_token_hard_expires_in.
"""

if self._include_refresh_token_hard_expires_in:
headers[INCLUDE_REFRESH_TOKEN_HARD_EXPIRES_IN_HEADER] = 'true'
return headers

def setAuthorizeURLs(self, urlObject):
"""Set authorization url using custom values passed in the data dict
:param **data: data dict for custom authorizationURLS
Expand Down Expand Up @@ -123,6 +163,9 @@ def get_bearer_token(self, auth_code, realm_id=None):
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': get_auth_header(self.client_id, self.client_secret)
}
headers = self._apply_refresh_token_hard_expires_in_header(
headers
)

body = {
'grant_type': 'authorization_code',
Expand All @@ -148,6 +191,9 @@ def refresh(self, refresh_token=None):
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': get_auth_header(self.client_id, self.client_secret)
}
headers = self._apply_refresh_token_hard_expires_in_header(
headers
)

body = {
'grant_type': 'refresh_token',
Expand Down
8 changes: 7 additions & 1 deletion intuitlib/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,10 @@
ACCEPT_HEADER = {
'Accept': 'application/json',
'User-Agent': '{0}-{1}-{2}-{3} {4} {5} {6}'.format('Intuit-OAuthClient', version.__version__,'Python', PYTHON_VERSION, OS_SYSTEM, OS_RELEASE_VER, OS_MACHINE)
}
}

# Header to request refresh token hard expiry info on token-endpoint calls
INCLUDE_REFRESH_TOKEN_HARD_EXPIRES_IN_HEADER = 'x-include-refresh-token-hard-expires-in'

# Response field key for the refresh token hard expiry lifespan (seconds)
X_REFRESH_TOKEN_HARD_EXPIRES_IN = 'x_refresh_token_hard_expires_in'
2 changes: 1 addition & 1 deletion intuitlib/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.

__version__ = '1.2.6'
__version__ = '1.2.7'