Skip to content

Commit 632592d

Browse files
committed
Fixed the refresh token flow
1 parent 5735e32 commit 632592d

File tree

4 files changed

+55
-13
lines changed

4 files changed

+55
-13
lines changed

CHANGELOG.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
Changelog
22
=========
33

4+
* Fixed a bug where the authentication refresh token flow did not update the token values
5+
46
v1.1.0 (2023-01-20)
57
-------------------
68

datacrunch/authentication/authentication.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def authenticate(self) -> dict:
4040
}
4141

4242
response = requests.post(
43-
url, data=payload, headers=self._generate_headers())
43+
url, json=payload, headers=self._generate_headers())
4444
handle_error(response)
4545

4646
auth_data = response.json()
@@ -56,6 +56,7 @@ def authenticate(self) -> dict:
5656
def refresh(self) -> dict:
5757
"""Authenticate the client using the refresh token - refresh the access token.
5858
59+
updates the object's tokens, and:
5960
returns an authentication data dictionary with the following schema:
6061
{
6162
"access_token": token str,
@@ -76,10 +77,18 @@ def refresh(self) -> dict:
7677
}
7778

7879
response = requests.post(
79-
url, data=payload, headers=self._generate_headers())
80+
url, json=payload, headers=self._generate_headers())
8081
handle_error(response)
8182

82-
return response.json()
83+
auth_data = response.json()
84+
85+
self._access_token = auth_data['access_token']
86+
self._refresh_token = auth_data['refresh_token']
87+
self._scope = auth_data['scope']
88+
self._token_type = auth_data['token_type']
89+
self._expires_at = time.time() + auth_data['expires_in']
90+
91+
return auth_data
8392

8493
def _generate_headers(self):
8594
# get the first 10 chars of the client id

datacrunch/http_client/http_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ def _refresh_token_if_expired(self) -> None:
148148
:raises APIException: an api exception with message and error type code
149149
"""
150150
if(self._auth_service.is_expired()):
151-
# to to refresh. if refresh token has expired, reauthenticate
151+
# try to refresh. if refresh token has expired, reauthenticate
152152
try:
153153
self._auth_service.refresh()
154154
except Exception:
@@ -181,8 +181,8 @@ def _generate_user_agent(self) -> str:
181181
:return: user agent string
182182
:rtype: str
183183
"""
184-
client_id_truncated = self._auth_service._client_id[:
185-
10] # get the first 10 chars of the client id
184+
# get the first 10 chars of the client id
185+
client_id_truncated = self._auth_service._client_id[:10]
186186

187187
return f'datacrunch-python-v{self._version}-{client_id_truncated}'
188188

tests/unit_tests/authentication/test_authentication.py

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import pytest
22
import responses # https://github.com/getsentry/responses
3+
from responses import matchers
34
import time
45

56
from datacrunch.exceptions import APIException
@@ -18,6 +19,9 @@
1819
TOKEN_TYPE = 'Bearer'
1920
EXPIRES_IN = 3600
2021

22+
ACCESS_TOKEN2 = 'access2'
23+
REFRESH_TOKEN2 = 'refresh2'
24+
2125
class TestAuthenticationService:
2226

2327
@pytest.fixture
@@ -74,9 +78,10 @@ def test_authenticate_failed(self, authentication_service, endpoint):
7478
assert excinfo.value.code == INVALID_REQUEST
7579
assert excinfo.value.message == INVALID_REQUEST_MESSAGE
7680
assert responses.assert_call_count(endpoint, 1) is True
77-
assert responses.calls[0].request.body == f'grant_type=client_credentials&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}'
81+
assert responses.calls[0].request.body == f'{{"grant_type": "client_credentials", "client_id": "{CLIENT_ID}", "client_secret": "{CLIENT_SECRET}"}}'.encode()
7882

7983
def test_refresh_successful(self, authentication_service, endpoint):
84+
# add a response for the client credentials grant
8085
responses.add(
8186
responses.POST,
8287
endpoint,
@@ -87,12 +92,27 @@ def test_refresh_successful(self, authentication_service, endpoint):
8792
'token_type': TOKEN_TYPE,
8893
'expires_in': EXPIRES_IN
8994
},
95+
match=[matchers.json_params_matcher({"grant_type":"client_credentials", "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET})],
96+
status=200
97+
)
98+
99+
# add another response for the refresh token grant
100+
responses.add(
101+
responses.POST,
102+
endpoint,
103+
json={
104+
'access_token': ACCESS_TOKEN2,
105+
'refresh_token': REFRESH_TOKEN2,
106+
'scope': SCOPE,
107+
'token_type': TOKEN_TYPE,
108+
'expires_in': EXPIRES_IN
109+
},
110+
match=[matchers.json_params_matcher({"grant_type":"refresh_token", "refresh_token": REFRESH_TOKEN})],
90111
status=200
91112
)
92113

93114
# act
94-
authentication_service.authenticate() # authenticate first
95-
auth_data = authentication_service.refresh() # refresh
115+
auth_data = authentication_service.authenticate() # authenticate first
96116

97117
# assert
98118
assert type(auth_data) == dict
@@ -101,8 +121,17 @@ def test_refresh_successful(self, authentication_service, endpoint):
101121
assert authentication_service._scope == SCOPE
102122
assert authentication_service._token_type == TOKEN_TYPE
103123
assert authentication_service._expires_at != None
104-
assert responses.calls[0].request.body == f'grant_type=client_credentials&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}'
105-
assert responses.calls[1].request.body == f'grant_type=refresh_token&refresh_token={REFRESH_TOKEN}'
124+
assert responses.calls[0].request.body == f'{{"grant_type": "client_credentials", "client_id": "{CLIENT_ID}", "client_secret": "{CLIENT_SECRET}"}}'.encode()
125+
126+
auth_data2 = authentication_service.refresh() # refresh
127+
128+
assert type(auth_data2) == dict
129+
assert authentication_service._access_token == ACCESS_TOKEN2
130+
assert authentication_service._refresh_token == REFRESH_TOKEN2
131+
assert authentication_service._scope == SCOPE
132+
assert authentication_service._token_type == TOKEN_TYPE
133+
assert authentication_service._expires_at != None
134+
assert responses.calls[1].request.body == f'{{"grant_type": "refresh_token", "refresh_token": "{REFRESH_TOKEN}"}}'.encode()
106135
assert responses.assert_call_count(endpoint, 2) is True
107136

108137
def test_refresh_failed(self, authentication_service, endpoint):
@@ -118,6 +147,7 @@ def test_refresh_failed(self, authentication_service, endpoint):
118147
'token_type': TOKEN_TYPE,
119148
'expires_in': EXPIRES_IN
120149
},
150+
match=[matchers.json_params_matcher({"grant_type":"client_credentials", "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET})],
121151
status=200
122152
)
123153

@@ -126,6 +156,7 @@ def test_refresh_failed(self, authentication_service, endpoint):
126156
responses.POST,
127157
endpoint,
128158
json={"code": INVALID_REQUEST, "message": INVALID_REQUEST_MESSAGE},
159+
match=[matchers.json_params_matcher({"grant_type":"refresh_token", "refresh_token": REFRESH_TOKEN})],
129160
status=400
130161
)
131162

@@ -139,8 +170,8 @@ def test_refresh_failed(self, authentication_service, endpoint):
139170
assert excinfo.value.code == INVALID_REQUEST
140171
assert excinfo.value.message == INVALID_REQUEST_MESSAGE
141172
assert responses.assert_call_count(endpoint, 2) is True
142-
assert responses.calls[0].request.body == f'grant_type=client_credentials&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}'
143-
assert responses.calls[1].request.body == f'grant_type=refresh_token&refresh_token={REFRESH_TOKEN}'
173+
assert responses.calls[0].request.body == f'{{"grant_type": "client_credentials", "client_id": "{CLIENT_ID}", "client_secret": "{CLIENT_SECRET}"}}'.encode()
174+
assert responses.calls[1].request.body == f'{{"grant_type": "refresh_token", "refresh_token": "{REFRESH_TOKEN}"}}'.encode()
144175

145176
def test_is_expired(self, authentication_service, endpoint):
146177
# arrange

0 commit comments

Comments
 (0)