Skip to content
Merged
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
1 change: 1 addition & 0 deletions descope/management/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class MgmtV1:
user_set_active_password_path = "/v1/mgmt/user/password/set/active"
user_expire_password_path = "/v1/mgmt/user/password/expire"
user_remove_all_passkeys_path = "/v1/mgmt/user/passkeys/delete"
user_remove_totp_seed_path = "/v1/mgmt/user/totp/delete"
user_add_tenant_path = "/v1/mgmt/user/update/tenant/add"
user_remove_tenant_path = "/v1/mgmt/user/update/tenant/remove"
user_generate_otp_for_test_path = "/v1/mgmt/tests/generate/otp"
Expand Down
22 changes: 22 additions & 0 deletions descope/management/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -1506,6 +1506,28 @@ def remove_all_passkeys(
)
return

def remove_totp_seed(
self,
login_id: str,
) -> None:
"""
Removes TOTP seed for the user with the given login ID.
Note: The user might not be able to login anymore if they have no other authentication
methods or a verified email/phone.

Args:
login_id (str): The login ID of the user to remove totp seed for.

Raise:
AuthException: raised if the operation fails
"""
self._auth.do_post(
MgmtV1.user_remove_totp_seed_path,
{"loginId": login_id},
pswd=self._auth.management_key,
)
return

def generate_otp_for_test_user(
self,
method: DeliveryMethod,
Expand Down
33 changes: 33 additions & 0 deletions tests/management/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -2181,6 +2181,39 @@ def test_user_remove_all_passkeys(self):
timeout=DEFAULT_TIMEOUT_SECONDS,
)

def test_user_remove_totp_seed(self):
# Test failed flows
with patch("requests.post") as mock_post:
mock_post.return_value.ok = False
self.assertRaises(
AuthException,
self.client.mgmt.user.remove_totp_seed,
"login-id",
)

# Test success flow
with patch("requests.post") as mock_post:
network_resp = mock.Mock()
network_resp.ok = True
mock_post.return_value = network_resp
self.client.mgmt.user.remove_totp_seed(
"login-id",
)
mock_post.assert_called_with(
f"{common.DEFAULT_BASE_URL}{MgmtV1.user_remove_totp_seed_path}",
headers={
**common.default_headers,
"Authorization": f"Bearer {self.dummy_project_id}:{self.dummy_management_key}",
},
params=None,
json={
"loginId": "login-id",
},
allow_redirects=False,
verify=True,
timeout=DEFAULT_TIMEOUT_SECONDS,
)

def test_generate_magic_link_for_test_user(self):
# Test failed flows
with patch("requests.post") as mock_post:
Expand Down
Loading