diff --git a/tests/test_passwordless.py b/tests/test_passwordless.py new file mode 100644 index 00000000..e8308b18 --- /dev/null +++ b/tests/test_passwordless.py @@ -0,0 +1,51 @@ +import json +from requests import Response + +import pytest + +import workos +from workos.passwordless import Passwordless + + +class TestPasswordless(object): + @pytest.fixture(autouse=True) + def setup(self, set_api_key_and_project_id): + self.passwordless = Passwordless() + + @pytest.fixture + def mock_passwordless_session(self): + return { + "id": "passwordless_session_01EHDAK2BFGWCSZXP9HGZ3VK8C", + "email": "demo@workos-okta.com", + "expires_at": "2020-08-13T05:50:00.000Z", + "link": "https://auth.workos.com/passwordless/4TeRexuejWCKs9rrFOIuLRYEr/confirm", + "object": "passwordless_session", + } + + def test_create_session_succeeds( + self, mock_passwordless_session, mock_request_method + ): + mock_response = Response() + mock_response.status_code = 201 + mock_response.response_dict = mock_passwordless_session + mock_request_method("post", mock_response, 201) + + session_options = { + "email": "demo@workos-okta.com", + "type": "MagicLink", + } + response = self.passwordless.create_session(session_options) + + assert response.status_code == 201 + assert response.response_dict == mock_passwordless_session + + def test_get_send_session_succeeds(self, mock_request_method): + response = { + "success": True, + } + mock_request_method("post", response, 200) + + response = self.passwordless.send_session( + "passwordless_session_01EHDAK2BFGWCSZXP9HGZ3VK8C" + ) + assert response == True diff --git a/workos/passwordless.py b/workos/passwordless.py new file mode 100644 index 00000000..cc220b78 --- /dev/null +++ b/workos/passwordless.py @@ -0,0 +1,59 @@ +import workos +from workos.utils.request import RequestHelper, REQUEST_METHOD_POST +from workos.utils.validation import PASSWORDLESS_MODULE, validate_settings + + +class Passwordless(object): + """Offers methods through the WorkOS Passwordless service.""" + + @validate_settings(PASSWORDLESS_MODULE) + def __init__(self): + pass + + @property + def request_helper(self): + if not getattr(self, "_request_helper", None): + self._request_helper = RequestHelper() + return self._request_helper + + def create_session(self, session_options): + """Create a Passwordless Session. + + Args: + session_options (dict) - An session options object + session_options[email] (str): The email of the user to authenticate. + session_options[state] (str): Optional parameter that the redirect + URI received from WorkOS will contain. The state parameter + can be used to encode arbitrary information to help + restore application state between redirects. + session_options[type] (str): The type of Passwordless Session to + create. Currently, the only supported value is 'MagicLink'. + + Returns: + dict: Passwordless Session + """ + + return self.request_helper.request( + "passwordless/sessions", + method=REQUEST_METHOD_POST, + params=session_options, + token=workos.api_key, + ) + + def send_session(self, session_id): + """Send a Passwordless Session via email. + + Args: + session_id (str): The unique identifier of the Passwordless + Session to send an email for. + + Returns: + boolean: Returns True + """ + self.request_helper.request( + "passwordless/sessions/{session_id}/send".format(session_id=session_id), + method=REQUEST_METHOD_POST, + token=workos.api_key, + ) + + return True diff --git a/workos/utils/validation.py b/workos/utils/validation.py index abacb531..7f4699e5 100644 --- a/workos/utils/validation.py +++ b/workos/utils/validation.py @@ -5,12 +5,14 @@ AUDIT_TRAIL_MODULE = "AuditTrail" DIRECTORY_SYNC_MODULE = "DirectorySync" +PASSWORDLESS_MODULE = "Passwordless" PORTAL_MODULE = "Portal" SSO_MODULE = "SSO" REQUIRED_SETTINGS_FOR_MODULE = { AUDIT_TRAIL_MODULE: ["api_key",], DIRECTORY_SYNC_MODULE: ["api_key",], + PASSWORDLESS_MODULE: ["api_key",], PORTAL_MODULE: ["api_key",], SSO_MODULE: ["api_key", "project_id",], }