From 253b72118acfca2b841c7a1fbe2b50bd890b9ffe Mon Sep 17 00:00:00 2001 From: dorsha Date: Wed, 13 Nov 2024 11:45:12 +0200 Subject: [PATCH] Logout previous sessions --- README.md | 6 ++++++ descope/common.py | 1 + descope/descope_client.py | 22 ++++++++++++++++++++++ tests/test_descope_client.py | 18 ++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/README.md b/README.md index 2f774868a..008a54564 100644 --- a/README.md +++ b/README.md @@ -472,6 +472,12 @@ invalidate all user's refresh tokens. After calling this function, you must inva descope_client.logout_all(refresh_token) ``` +It is also possible to sign the user out from all previous sessions. + +```python +descope_client.logout_previous(refresh_token) +``` + ### History You can get the current session user history. diff --git a/descope/common.py b/descope/common.py index 828096e4a..27f72d6b2 100644 --- a/descope/common.py +++ b/descope/common.py @@ -25,6 +25,7 @@ class EndpointsV1: select_tenant_path = "/v1/auth/tenant/select" logout_path = "/v1/auth/logout" logout_all_path = "/v1/auth/logoutall" + logout_previous_path = "/v1/auth/logoutprevious" me_path = "/v1/auth/me" my_tenants_path = "/v1/auth/me/tenants" history_path = "/v1/auth/me/history" diff --git a/descope/descope_client.py b/descope/descope_client.py index ddc488782..76598a265 100644 --- a/descope/descope_client.py +++ b/descope/descope_client.py @@ -408,6 +408,28 @@ def logout_all(self, refresh_token: str) -> requests.Response: uri = EndpointsV1.logout_all_path return self._auth.do_post(uri, {}, None, refresh_token) + def logout_previous(self, refresh_token: str) -> requests.Response: + """ + Logout user from previous active sessions. + + Args: + refresh_token (str): The refresh token + + Return value (requests.Response): returns the response from the Descope server + + Raise: + AuthException: Exception is raised if session is not authorized or another error occurs + """ + if refresh_token is None: + raise AuthException( + 400, + ERROR_TYPE_INVALID_ARGUMENT, + f"signed refresh token {refresh_token} is empty", + ) + + uri = EndpointsV1.logout_previous_path + return self._auth.do_post(uri, {}, None, refresh_token) + def me(self, refresh_token: str) -> dict: """ Retrieve user details for the refresh token. The returned data includes email, name, phone, diff --git a/tests/test_descope_client.py b/tests/test_descope_client.py index 9aa2bb6e3..9c07eefb0 100644 --- a/tests/test_descope_client.py +++ b/tests/test_descope_client.py @@ -100,6 +100,24 @@ def test_logout_all(self): mock_post.return_value.ok = True self.assertIsNotNone(client.logout_all(dummy_refresh_token)) + def test_logout_previous(self): + dummy_refresh_token = "" + client = DescopeClient(self.dummy_project_id, self.public_key_dict) + + self.assertRaises(AuthException, client.logout_previous, None) + + # Test failed flow + with patch("requests.post") as mock_post: + mock_post.return_value.ok = False + self.assertRaises( + AuthException, client.logout_previous, dummy_refresh_token + ) + + # Test success flow + with patch("requests.post") as mock_post: + mock_post.return_value.ok = True + self.assertIsNotNone(client.logout_previous(dummy_refresh_token)) + def test_me(self): dummy_refresh_token = "" client = DescopeClient(self.dummy_project_id, self.public_key_dict)