Skip to content

Commit 8531622

Browse files
dorshaclaude
andauthored
feat: add remove_recovery_codes user management method (#1643)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 18c4211 commit 8531622

5 files changed

Lines changed: 78 additions & 0 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,14 @@ Pass the loginId to the function to remove the user's TOTP seed.
304304
response = descope_client.mgmt.user.remove_totp_seed(login_id=login_id)
305305
```
306306

307+
#### Deleting Recovery Codes
308+
309+
Pass the loginId to the function to revoke all of the user's recovery codes.
310+
311+
```python
312+
response = descope_client.mgmt.user.remove_recovery_codes(login_id=login_id)
313+
```
314+
307315
### Passwords
308316

309317
The user can also authenticate with a password, though it's recommended to

descope/management/common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ class MgmtV1:
177177
user_expire_password_path = "/v1/mgmt/user/password/expire"
178178
user_remove_all_passkeys_path = "/v1/mgmt/user/passkeys/delete"
179179
user_remove_totp_seed_path = "/v1/mgmt/user/totp/delete"
180+
user_remove_recovery_codes_path = "/v1/mgmt/user/recovery-codes/delete"
180181
user_add_tenant_path = "/v1/mgmt/user/update/tenant/add"
181182
user_remove_tenant_path = "/v1/mgmt/user/update/tenant/remove"
182183
user_generate_otp_for_test_path = "/v1/mgmt/tests/generate/otp"

descope/management/user.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,6 +1580,25 @@ def remove_totp_seed(
15801580
)
15811581
return
15821582

1583+
def remove_recovery_codes(
1584+
self,
1585+
login_id: str,
1586+
) -> None:
1587+
"""
1588+
Removes all recovery codes for the user with the given login ID.
1589+
1590+
Args:
1591+
login_id (str): The login ID of the user to remove recovery codes for.
1592+
1593+
Raise:
1594+
AuthException: raised if the operation fails
1595+
"""
1596+
self._http.post(
1597+
MgmtV1.user_remove_recovery_codes_path,
1598+
body={"loginId": login_id},
1599+
)
1600+
return
1601+
15831602
def generate_otp_for_test_user(
15841603
self,
15851604
method: DeliveryMethod,

descope/management/user_async.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,6 +1586,25 @@ async def remove_totp_seed(
15861586
)
15871587
return
15881588

1589+
async def remove_recovery_codes(
1590+
self,
1591+
login_id: str,
1592+
) -> None:
1593+
"""
1594+
Removes all recovery codes for the user with the given login ID.
1595+
1596+
Args:
1597+
login_id (str): The login ID of the user to remove recovery codes for.
1598+
1599+
Raise:
1600+
AuthException: raised if the operation fails
1601+
"""
1602+
await self._http.post(
1603+
MgmtV1.user_remove_recovery_codes_path,
1604+
body={"loginId": login_id},
1605+
)
1606+
return
1607+
15891608
async def generate_otp_for_test_user(
15901609
self,
15911610
method: DeliveryMethod,

tests/management/test_user.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2239,6 +2239,37 @@ async def test_user_remove_totp_seed(self, client_factory):
22392239
follow_redirects=False,
22402240
)
22412241

2242+
async def test_user_remove_recovery_codes(self, client_factory):
2243+
client = client_factory.make(PROJECT_ID, PUBLIC_KEY_DICT, False, "key")
2244+
2245+
# Test failed flows
2246+
with client.mock_mgmt_post(make_response(status=500)) as mock_post:
2247+
with pytest.raises(AuthException):
2248+
await client.invoke(client.mgmt.user.remove_recovery_codes("login-id"))
2249+
2250+
# Test success flow
2251+
with client.mock_mgmt_post(make_response({})) as mock_post:
2252+
await client.invoke(
2253+
client.mgmt.user.remove_recovery_codes(
2254+
"login-id",
2255+
)
2256+
)
2257+
assert_http_called(
2258+
mock_post,
2259+
client.mode,
2260+
f"{DEFAULT_BASE_URL}{MgmtV1.user_remove_recovery_codes_path}",
2261+
headers={
2262+
**default_headers,
2263+
"Authorization": f"Bearer {PROJECT_ID}:key",
2264+
"x-descope-project-id": PROJECT_ID,
2265+
},
2266+
params=None,
2267+
json={
2268+
"loginId": "login-id",
2269+
},
2270+
follow_redirects=False,
2271+
)
2272+
22422273
async def test_generate_magic_link_for_test_user(self, client_factory):
22432274
client = client_factory.make(PROJECT_ID, PUBLIC_KEY_DICT, False, "key")
22442275

0 commit comments

Comments
 (0)