Skip to content

Commit f5f08e1

Browse files
ckieedorsha
andauthored
Support Descoper & Mgmt Key methods (#717)
Co-authored-by: Doron Sharon <[email protected]>
1 parent e185a7a commit f5f08e1

File tree

12 files changed

+1706
-0
lines changed

12 files changed

+1706
-0
lines changed

README.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ These sections show how to use the SDK to perform permission and user management
8484
14. [Manage Project](#manage-project)
8585
15. [Manage SSO Applications](#manage-sso-applications)
8686
16. [Manage Outbound Applications](#manage-outbound-applications)
87+
17. [Manage Descopers](#manage-descopers)
88+
18. [Manage Management Keys](#manage-management-keys)
8789

8890
If you wish to run any of our code samples and play with them, check out our [Code Examples](#code-examples) section.
8991

@@ -1565,6 +1567,141 @@ latest_tenant_token = descope_client.mgmt.outbound_application_by_token.fetch_te
15651567
)
15661568
```
15671569

1570+
### Manage Descopers
1571+
1572+
You can create, update, delete, load or list Descopers (users who have access to the Descope console):
1573+
1574+
```python
1575+
from descope import (
1576+
DescoperAttributes,
1577+
DescoperCreate,
1578+
DescoperProjectRole,
1579+
DescoperRBAC,
1580+
DescoperRole,
1581+
)
1582+
1583+
# Create a new Descoper
1584+
resp = descope_client.mgmt.descoper.create(
1585+
descopers=[
1586+
DescoperCreate(
1587+
login_id="[email protected]",
1588+
attributes=DescoperAttributes(
1589+
display_name="John Doe",
1590+
1591+
phone="+1234567890",
1592+
),
1593+
send_invite=True, # Send an invitation email
1594+
rbac=DescoperRBAC(
1595+
is_company_admin=False,
1596+
projects=[
1597+
DescoperProjectRole(
1598+
project_ids=["project-id-1"],
1599+
role=DescoperRole.ADMIN,
1600+
)
1601+
],
1602+
),
1603+
)
1604+
]
1605+
)
1606+
descopers = resp["descopers"]
1607+
total = resp["total"]
1608+
1609+
# Load a Descoper by ID
1610+
resp = descope_client.mgmt.descoper.load("descoper-id")
1611+
descoper = resp["descoper"]
1612+
1613+
# Update a Descoper's attributes and/or RBAC
1614+
# Note: All fields that are set will override existing values
1615+
resp = descope_client.mgmt.descoper.update(
1616+
id="descoper-id",
1617+
attributes=DescoperAttributes(
1618+
display_name="Updated Name",
1619+
),
1620+
rbac=DescoperRBAC(
1621+
is_company_admin=True,
1622+
),
1623+
)
1624+
updated_descoper = resp["descoper"]
1625+
1626+
# List all Descopers
1627+
resp = descope_client.mgmt.descoper.list()
1628+
descopers = resp["descopers"]
1629+
total = resp["total"]
1630+
for descoper in descopers:
1631+
# Do something
1632+
1633+
# Delete a Descoper
1634+
# Descoper deletion cannot be undone. Use carefully.
1635+
descope_client.mgmt.descoper.delete("descoper-id")
1636+
```
1637+
1638+
### Manage Management Keys
1639+
1640+
You can create, update, delete, load or search management keys:
1641+
1642+
```python
1643+
from descope import (
1644+
MgmtKeyReBac,
1645+
MgmtKeyProjectRole,
1646+
MgmtKeyTagRole,
1647+
MgmtKeyStatus,
1648+
)
1649+
1650+
# Create a new management key with RBAC configuration
1651+
# The rebac parameter defines the key's access permissions
1652+
rebac = MgmtKeyReBac(
1653+
company_roles=["company-full-access"], # Company-level roles
1654+
project_roles=[ # Project-specific roles
1655+
MgmtKeyProjectRole(
1656+
project_ids=["project-id-1", "project-id-2"],
1657+
roles=["project-admin"]
1658+
)
1659+
],
1660+
tag_roles=[ # Tag-based roles
1661+
MgmtKeyTagRole(
1662+
tags=["production"],
1663+
roles=["read-only"]
1664+
)
1665+
],
1666+
)
1667+
1668+
create_resp = descope_client.mgmt.management_key.create(
1669+
name="My Management Key",
1670+
rebac=rebac,
1671+
description="Optional description for the management key",
1672+
expires_in=0, # Expiration time in seconds (0 for no expiration)
1673+
permitted_ips=["10.0.0.1", "192.168.1.0/24"], # Optional IP allowlist
1674+
)
1675+
key = create_resp["key"]
1676+
cleartext = create_resp["cleartext"] # Save this securely - it will not be returned again!
1677+
1678+
# Load a specific management key by ID
1679+
load_resp = descope_client.mgmt.management_key.load("key-id")
1680+
loaded_key = load_resp["key"]
1681+
1682+
# Search all management keys
1683+
search_resp = descope_client.mgmt.management_key.search()
1684+
keys = search_resp["keys"]
1685+
for key in keys:
1686+
# Do something
1687+
1688+
# Update a management key
1689+
# IMPORTANT: All parameters will override existing values. Use carefully.
1690+
update_resp = descope_client.mgmt.management_key.update(
1691+
id="key-id",
1692+
name="Updated Key Name",
1693+
description="Updated description",
1694+
permitted_ips=["10.0.0.2"],
1695+
status=MgmtKeyStatus.ACTIVE, # Can be ACTIVE or INACTIVE
1696+
)
1697+
updated_key = update_resp["key"]
1698+
1699+
# Delete management keys
1700+
# IMPORTANT: This action is irreversible. Use carefully.
1701+
delete_resp = descope_client.mgmt.management_key.delete(["key-id-1", "key-id-2"])
1702+
total_deleted = delete_resp["total"]
1703+
```
1704+
15681705
### Utils for your end to end (e2e) tests and integration tests
15691706

15701707
To ease your e2e tests, we exposed dedicated management methods,

descope/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@
2020
from descope.http_client import DescopeResponse
2121
from descope.management.common import (
2222
AssociatedTenant,
23+
DescoperAttributes,
24+
DescoperCreate,
25+
DescoperProjectRole,
26+
DescoperRBAC,
27+
DescoperRole,
28+
DescoperTagRole,
29+
MgmtKeyProjectRole,
30+
MgmtKeyReBac,
31+
MgmtKeyStatus,
32+
MgmtKeyTagRole,
2333
SAMLIDPAttributeMappingInfo,
2434
SAMLIDPGroupsMappingInfo,
2535
SAMLIDPRoleGroupMappingInfo,

descope/http_client.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,26 @@ def post(
219219
self._raise_from_response(response)
220220
return response
221221

222+
def put(
223+
self,
224+
uri: str,
225+
*,
226+
body: dict | list[dict] | list[str] | None = None,
227+
params=None,
228+
pswd: str | None = None,
229+
) -> requests.Response:
230+
response = requests.put(
231+
f"{self.base_url}{uri}",
232+
headers=self._get_default_headers(pswd),
233+
json=body,
234+
allow_redirects=False,
235+
verify=self.secure,
236+
params=params,
237+
timeout=self.timeout_seconds,
238+
)
239+
self._raise_from_response(response)
240+
return response
241+
222242
def patch(
223243
self,
224244
uri: str,
@@ -245,12 +265,14 @@ def delete(
245265
self,
246266
uri: str,
247267
*,
268+
body: dict | list[dict] | list[str] | None = None,
248269
params=None,
249270
pswd: str | None = None,
250271
) -> requests.Response:
251272
response = requests.delete(
252273
f"{self.base_url}{uri}",
253274
params=params,
275+
json=body,
254276
headers=self._get_default_headers(pswd),
255277
allow_redirects=False,
256278
verify=self.secure,

0 commit comments

Comments
 (0)