Skip to content

Commit 9e51db3

Browse files
authored
Logout previous sessions (#457)
1 parent d3305fa commit 9e51db3

File tree

4 files changed

+47
-0
lines changed

4 files changed

+47
-0
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,12 @@ invalidate all user's refresh tokens. After calling this function, you must inva
472472
descope_client.logout_all(refresh_token)
473473
```
474474

475+
It is also possible to sign the user out from all previous sessions.
476+
477+
```python
478+
descope_client.logout_previous(refresh_token)
479+
```
480+
475481
### History
476482

477483
You can get the current session user history.

descope/common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class EndpointsV1:
2525
select_tenant_path = "/v1/auth/tenant/select"
2626
logout_path = "/v1/auth/logout"
2727
logout_all_path = "/v1/auth/logoutall"
28+
logout_previous_path = "/v1/auth/logoutprevious"
2829
me_path = "/v1/auth/me"
2930
my_tenants_path = "/v1/auth/me/tenants"
3031
history_path = "/v1/auth/me/history"

descope/descope_client.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,28 @@ def logout_all(self, refresh_token: str) -> requests.Response:
408408
uri = EndpointsV1.logout_all_path
409409
return self._auth.do_post(uri, {}, None, refresh_token)
410410

411+
def logout_previous(self, refresh_token: str) -> requests.Response:
412+
"""
413+
Logout user from previous active sessions.
414+
415+
Args:
416+
refresh_token (str): The refresh token
417+
418+
Return value (requests.Response): returns the response from the Descope server
419+
420+
Raise:
421+
AuthException: Exception is raised if session is not authorized or another error occurs
422+
"""
423+
if refresh_token is None:
424+
raise AuthException(
425+
400,
426+
ERROR_TYPE_INVALID_ARGUMENT,
427+
f"signed refresh token {refresh_token} is empty",
428+
)
429+
430+
uri = EndpointsV1.logout_previous_path
431+
return self._auth.do_post(uri, {}, None, refresh_token)
432+
411433
def me(self, refresh_token: str) -> dict:
412434
"""
413435
Retrieve user details for the refresh token. The returned data includes email, name, phone,

tests/test_descope_client.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,24 @@ def test_logout_all(self):
100100
mock_post.return_value.ok = True
101101
self.assertIsNotNone(client.logout_all(dummy_refresh_token))
102102

103+
def test_logout_previous(self):
104+
dummy_refresh_token = ""
105+
client = DescopeClient(self.dummy_project_id, self.public_key_dict)
106+
107+
self.assertRaises(AuthException, client.logout_previous, None)
108+
109+
# Test failed flow
110+
with patch("requests.post") as mock_post:
111+
mock_post.return_value.ok = False
112+
self.assertRaises(
113+
AuthException, client.logout_previous, dummy_refresh_token
114+
)
115+
116+
# Test success flow
117+
with patch("requests.post") as mock_post:
118+
mock_post.return_value.ok = True
119+
self.assertIsNotNone(client.logout_previous(dummy_refresh_token))
120+
103121
def test_me(self):
104122
dummy_refresh_token = ""
105123
client = DescopeClient(self.dummy_project_id, self.public_key_dict)

0 commit comments

Comments
 (0)