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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1113,7 +1113,7 @@ Embedded links can be created to directly receive a verifiable token without sen
This token can then be verified using the magic link 'verify' function, either directly or through a flow.

```python
token = descope_client.mgmt.user.generate_embedded_link("[email protected]", {"key1":"value1"})
token = descope_client.mgmt.user.generate_embedded_link("[email protected]", {"key1":"value1"}, 120)
```

### Audit
Expand Down
1 change: 1 addition & 0 deletions descope/management/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class MgmtV1:
user_generate_magic_link_for_test_path = "/v1/mgmt/tests/generate/magiclink"
user_generate_enchanted_link_for_test_path = "/v1/mgmt/tests/generate/enchantedlink"
user_generate_embedded_link_path = "/v1/mgmt/user/signin/embeddedlink"
user_generate_sign_up_embedded_link_path = "/v1/mgmt/user/signup/embeddedlink"
user_history_path = "/v1/mgmt/user/history"

# access key
Expand Down
59 changes: 57 additions & 2 deletions descope/management/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,24 @@
self.status = status


class CreateUserObj:
def __init__(
self,
email: Optional[str] = None,
phone: Optional[str] = None,
name: Optional[str] = None,
given_name: Optional[str] = None,
middle_name: Optional[str] = None,
family_name: Optional[str] = None,
):
self.email = email

Check warning on line 69 in descope/management/user.py

View workflow job for this annotation

GitHub Actions / Coverage

This line has no coverage
self.phone = phone

Check warning on line 70 in descope/management/user.py

View workflow job for this annotation

GitHub Actions / Coverage

This line has no coverage
self.name = name

Check warning on line 71 in descope/management/user.py

View workflow job for this annotation

GitHub Actions / Coverage

This line has no coverage
self.given_name = given_name

Check warning on line 72 in descope/management/user.py

View workflow job for this annotation

GitHub Actions / Coverage

This line has no coverage
self.middle_name = middle_name

Check warning on line 73 in descope/management/user.py

View workflow job for this annotation

GitHub Actions / Coverage

This line has no coverage
self.family_name = family_name

Check warning on line 74 in descope/management/user.py

View workflow job for this annotation

GitHub Actions / Coverage

This line has no coverage


class User(AuthBase):
def create(
self,
Expand Down Expand Up @@ -1655,7 +1673,7 @@
return response.json()

def generate_embedded_link(
self, login_id: str, custom_claims: Optional[dict] = None
self, login_id: str, custom_claims: Optional[dict] = None, timeout: int = 0
) -> str:
"""
Generate Embedded Link for the given user login ID.
Expand All @@ -1673,7 +1691,44 @@
"""
response = self._auth.do_post(
MgmtV1.user_generate_embedded_link_path,
{"loginId": login_id, "customClaims": custom_claims},
{"loginId": login_id, "customClaims": custom_claims, "timeout": timeout},
pswd=self._auth.management_key,
)
return response.json()["token"]

def generate_sign_up_embedded_link(
self, login_id: str, user: Optional[CreateUserObj] = None,
email_verified: bool = False, phone_verified: bool = False,
login_options: Optional[LoginOptions] = None, timeout: int = 0
) -> str:
"""
Generate sign up Embedded Link for the given user login ID.
The return value is a token that can be verified via magic link, or using flows

Args:
login_id (str): The login ID of the user to authenticate with.
user (CreateUserObj): Optional user object to create the user with
email_verified (bool): Optional, set to true if the email is verified
phone_verified (bool): Optional, set to true if the phone is verified
login_options (LoginOptions): Optional login options to customize the link
timeout (int): Optional, the timeout in seconds for the link to be valid

Return value (str):
Return the token to be used in verification process

Raise:
AuthException: raised if the operation fails
"""
response = self._auth.do_post(
MgmtV1.user_generate_sign_up_embedded_link_path,
{
"loginId": login_id,
"user": user.__dict__ if user else {},
"loginOptions": login_options.__dict__ if login_options else {},
"emailVerified": email_verified,
"phoneVerified": phone_verified,
"timeout": timeout
},
pswd=self._auth.management_key,
)
return response.json()["token"]
Expand Down
40 changes: 40 additions & 0 deletions tests/management/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -2406,6 +2406,46 @@ def test_generate_embedded_link(self):
json={
"loginId": "login-id",
"customClaims": {"k1": "v1"},
"timeout": 0,
},
allow_redirects=False,
verify=True,
params=None,
timeout=DEFAULT_TIMEOUT_SECONDS,
)

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

# Test success flow
with patch("requests.post") as mock_post:
network_resp = mock.Mock()
network_resp.ok = True
network_resp.json.return_value = json.loads("""{"token": "some-token"}""")
mock_post.return_value = network_resp
resp = self.client.mgmt.user.generate_sign_up_embedded_link(
"login-id", email_verified=True, phone_verified=True
)
self.assertEqual(resp, "some-token")
mock_post.assert_called_with(
f"{common.DEFAULT_BASE_URL}{MgmtV1.user_generate_sign_up_embedded_link_path}",
headers={
**common.default_headers,
"Authorization": f"Bearer {self.dummy_project_id}:{self.dummy_management_key}",
"x-descope-project-id": self.dummy_project_id,
},
json={
"loginId": "login-id",
"phoneVerified": True,
"emailVerified": True,
"user": {},
"loginOptions": {},
"timeout": 0,
},
allow_redirects=False,
verify=True,
Expand Down
Loading