Skip to content

Commit 9d6229e

Browse files
committed
implementation
1 parent 607065f commit 9d6229e

23 files changed

+5833
-154
lines changed

descope/auth.py

Lines changed: 393 additions & 0 deletions
Large diffs are not rendered by default.

descope/authmethod/enchantedlink.py

Lines changed: 120 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,28 @@ def sign_in(
3939
response = self._auth.do_post(uri, body, None, refresh_token)
4040
return EnchantedLink._get_pending_ref_from_response(response)
4141

42+
async def sign_in_async(
43+
self,
44+
login_id: str,
45+
uri: str,
46+
login_options: LoginOptions | None = None,
47+
refresh_token: str | None = None,
48+
) -> dict:
49+
if not login_id:
50+
raise AuthException(
51+
400,
52+
ERROR_TYPE_INVALID_ARGUMENT,
53+
"login_id is empty",
54+
)
55+
56+
validate_refresh_token_provided(login_options, refresh_token)
57+
58+
body = EnchantedLink._compose_signin_body(login_id, uri, login_options)
59+
uri = EnchantedLink._compose_signin_url()
60+
61+
response = await self._auth.do_post_async(uri, body, None, refresh_token)
62+
return EnchantedLink._get_pending_ref_from_response(response)
63+
4264
def sign_up(
4365
self,
4466
login_id: str,
@@ -63,6 +85,30 @@ def sign_up(
6385
response = self._auth.do_post(uri, body, None)
6486
return EnchantedLink._get_pending_ref_from_response(response)
6587

88+
async def sign_up_async(
89+
self,
90+
login_id: str,
91+
uri: str,
92+
user: dict | None,
93+
signup_options: SignUpOptions | None = None,
94+
) -> dict:
95+
if not user:
96+
user = {}
97+
98+
if not self._auth.adjust_and_verify_delivery_method(
99+
DeliveryMethod.EMAIL, login_id, user
100+
):
101+
raise AuthException(
102+
400,
103+
ERROR_TYPE_INVALID_ARGUMENT,
104+
f"Login ID {login_id} is not valid for email",
105+
)
106+
107+
body = EnchantedLink._compose_signup_body(login_id, uri, user, signup_options)
108+
uri = EnchantedLink._compose_signup_url()
109+
response = await self._auth.do_post_async(uri, body, None)
110+
return EnchantedLink._get_pending_ref_from_response(response)
111+
66112
def sign_up_or_in(
67113
self, login_id: str, uri: str, signup_options: SignUpOptions | None = None
68114
) -> dict:
@@ -83,6 +129,26 @@ def sign_up_or_in(
83129
response = self._auth.do_post(uri, body, None)
84130
return EnchantedLink._get_pending_ref_from_response(response)
85131

132+
async def sign_up_or_in_async(
133+
self, login_id: str, uri: str, signup_options: SignUpOptions | None = None
134+
) -> dict:
135+
login_options: LoginOptions | None = None
136+
if signup_options is not None:
137+
login_options = LoginOptions(
138+
custom_claims=signup_options.customClaims,
139+
template_options=signup_options.templateOptions,
140+
template_id=signup_options.templateId,
141+
)
142+
143+
body = EnchantedLink._compose_signin_body(
144+
login_id,
145+
uri,
146+
login_options,
147+
)
148+
uri = EnchantedLink._compose_sign_up_or_in_url()
149+
response = await self._auth.do_post_async(uri, body, None)
150+
return EnchantedLink._get_pending_ref_from_response(response)
151+
86152
def get_session(self, pending_ref: str) -> dict:
87153
uri = EndpointsV1.get_session_enchantedlink_auth_path
88154
body = EnchantedLink._compose_get_session_body(pending_ref)
@@ -94,11 +160,27 @@ def get_session(self, pending_ref: str) -> dict:
94160
)
95161
return jwt_response
96162

163+
async def get_session_async(self, pending_ref: str) -> dict:
164+
uri = EndpointsV1.get_session_enchantedlink_auth_path
165+
body = EnchantedLink._compose_get_session_body(pending_ref)
166+
response = await self._auth.do_post_async(uri, body, None)
167+
168+
resp = response.json()
169+
jwt_response = await self._auth.generate_jwt_response_async(
170+
resp, response.cookies.get(REFRESH_SESSION_COOKIE_NAME, None), None
171+
)
172+
return jwt_response
173+
97174
def verify(self, token: str):
98175
uri = EndpointsV1.verify_enchantedlink_auth_path
99176
body = EnchantedLink._compose_verify_body(token)
100177
self._auth.do_post(uri, body, None)
101178

179+
async def verify_async(self, token: str):
180+
uri = EndpointsV1.verify_enchantedlink_auth_path
181+
body = EnchantedLink._compose_verify_body(token)
182+
await self._auth.do_post_async(uri, body, None)
183+
102184
def update_user_email(
103185
self,
104186
login_id: str,
@@ -118,13 +200,49 @@ def update_user_email(
118200
Auth.validate_email(email)
119201

120202
body = EnchantedLink._compose_update_user_email_body(
121-
login_id, email, add_to_login_ids, on_merge_use_existing,
122-
template_options, template_id, provider_id
203+
login_id,
204+
email,
205+
add_to_login_ids,
206+
on_merge_use_existing,
207+
template_options,
208+
template_id,
209+
provider_id,
123210
)
124211
uri = EndpointsV1.update_user_email_enchantedlink_path
125212
response = self._auth.do_post(uri, body, None, refresh_token)
126213
return EnchantedLink._get_pending_ref_from_response(response)
127214

215+
async def update_user_email_async(
216+
self,
217+
login_id: str,
218+
email: str,
219+
refresh_token: str,
220+
add_to_login_ids: bool = False,
221+
on_merge_use_existing: bool = False,
222+
template_options: dict | None = None,
223+
template_id: str | None = None,
224+
provider_id: str | None = None,
225+
) -> dict:
226+
if not login_id:
227+
raise AuthException(
228+
400, ERROR_TYPE_INVALID_ARGUMENT, "Identifier cannot be empty"
229+
)
230+
231+
Auth.validate_email(email)
232+
233+
body = EnchantedLink._compose_update_user_email_body(
234+
login_id,
235+
email,
236+
add_to_login_ids,
237+
on_merge_use_existing,
238+
template_options,
239+
template_id,
240+
provider_id,
241+
)
242+
uri = EndpointsV1.update_user_email_enchantedlink_path
243+
response = await self._auth.do_post_async(uri, body, None, refresh_token)
244+
return EnchantedLink._get_pending_ref_from_response(response)
245+
128246
@staticmethod
129247
def _compose_signin_url() -> str:
130248
return Auth.compose_url(

descope/authmethod/magiclink.py

Lines changed: 160 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,29 @@ def sign_in(
4040
response = self._auth.do_post(uri, body, None, refresh_token)
4141
return Auth.extract_masked_address(response.json(), method)
4242

43+
async def sign_in_async(
44+
self,
45+
method: DeliveryMethod,
46+
login_id: str,
47+
uri: str,
48+
login_options: LoginOptions | None = None,
49+
refresh_token: str | None = None,
50+
) -> str:
51+
if not login_id:
52+
raise AuthException(
53+
400,
54+
ERROR_TYPE_INVALID_ARGUMENT,
55+
"Identifier is empty",
56+
)
57+
58+
validate_refresh_token_provided(login_options, refresh_token)
59+
60+
body = MagicLink._compose_signin_body(login_id, uri, login_options)
61+
uri = MagicLink._compose_signin_url(method)
62+
63+
response = await self._auth.do_post_async(uri, body, None, refresh_token)
64+
return Auth.extract_masked_address(response.json(), method)
65+
4366
def sign_up(
4467
self,
4568
method: DeliveryMethod,
@@ -65,6 +88,31 @@ def sign_up(
6588
response = self._auth.do_post(uri, body, None)
6689
return Auth.extract_masked_address(response.json(), method)
6790

91+
async def sign_up_async(
92+
self,
93+
method: DeliveryMethod,
94+
login_id: str,
95+
uri: str,
96+
user: dict | None = None,
97+
signup_options: SignUpOptions | None = None,
98+
) -> str:
99+
if not user:
100+
user = {}
101+
102+
if not self._auth.adjust_and_verify_delivery_method(method, login_id, user):
103+
raise AuthException(
104+
400,
105+
ERROR_TYPE_INVALID_ARGUMENT,
106+
f"Login ID {login_id} is not valid by delivery method {method}",
107+
)
108+
109+
body = MagicLink._compose_signup_body(
110+
method, login_id, uri, user, signup_options
111+
)
112+
uri = MagicLink._compose_signup_url(method)
113+
response = await self._auth.do_post_async(uri, body, None)
114+
return Auth.extract_masked_address(response.json(), method)
115+
68116
def sign_up_or_in(
69117
self,
70118
method: DeliveryMethod,
@@ -88,6 +136,29 @@ def sign_up_or_in(
88136
response = self._auth.do_post(uri, body, None)
89137
return Auth.extract_masked_address(response.json(), method)
90138

139+
async def sign_up_or_in_async(
140+
self,
141+
method: DeliveryMethod,
142+
login_id: str,
143+
uri: str,
144+
signup_options: SignUpOptions | None = None,
145+
) -> str:
146+
login_options: LoginOptions | None = None
147+
if signup_options is not None:
148+
login_options = LoginOptions(
149+
custom_claims=signup_options.customClaims,
150+
template_options=signup_options.templateOptions,
151+
template_id=signup_options.templateId,
152+
)
153+
body = MagicLink._compose_signin_body(
154+
login_id,
155+
uri,
156+
login_options,
157+
)
158+
uri = MagicLink._compose_sign_up_or_in_url(method)
159+
response = await self._auth.do_post_async(uri, body, None)
160+
return Auth.extract_masked_address(response.json(), method)
161+
91162
def verify(self, token: str, audience: str | None | Iterable[str] = None) -> dict:
92163
uri = EndpointsV1.verify_magiclink_auth_path
93164
body = MagicLink._compose_verify_body(token)
@@ -98,6 +169,18 @@ def verify(self, token: str, audience: str | None | Iterable[str] = None) -> dic
98169
)
99170
return jwt_response
100171

172+
async def verify_async(
173+
self, token: str, audience: str | None | Iterable[str] = None
174+
) -> dict:
175+
uri = EndpointsV1.verify_magiclink_auth_path
176+
body = MagicLink._compose_verify_body(token)
177+
response = await self._auth.do_post_async(uri, body, None)
178+
resp = response.json()
179+
jwt_response = await self._auth.generate_jwt_response_async(
180+
resp, response.cookies.get(REFRESH_SESSION_COOKIE_NAME, None), audience
181+
)
182+
return jwt_response
183+
101184
def update_user_email(
102185
self,
103186
login_id: str,
@@ -117,13 +200,49 @@ def update_user_email(
117200
Auth.validate_email(email)
118201

119202
body = MagicLink._compose_update_user_email_body(
120-
login_id, email, add_to_login_ids, on_merge_use_existing,
121-
template_options, template_id, provider_id
203+
login_id,
204+
email,
205+
add_to_login_ids,
206+
on_merge_use_existing,
207+
template_options,
208+
template_id,
209+
provider_id,
122210
)
123211
uri = EndpointsV1.update_user_email_magiclink_path
124212
response = self._auth.do_post(uri, body, None, refresh_token)
125213
return Auth.extract_masked_address(response.json(), DeliveryMethod.EMAIL)
126214

215+
async def update_user_email_async(
216+
self,
217+
login_id: str,
218+
email: str,
219+
refresh_token: str,
220+
add_to_login_ids: bool = False,
221+
on_merge_use_existing: bool = False,
222+
template_options: dict | None = None,
223+
template_id: str | None = None,
224+
provider_id: str | None = None,
225+
) -> str:
226+
if not login_id:
227+
raise AuthException(
228+
400, ERROR_TYPE_INVALID_ARGUMENT, "Identifier cannot be empty"
229+
)
230+
231+
Auth.validate_email(email)
232+
233+
body = MagicLink._compose_update_user_email_body(
234+
login_id,
235+
email,
236+
add_to_login_ids,
237+
on_merge_use_existing,
238+
template_options,
239+
template_id,
240+
provider_id,
241+
)
242+
uri = EndpointsV1.update_user_email_magiclink_path
243+
response = await self._auth.do_post_async(uri, body, None, refresh_token)
244+
return Auth.extract_masked_address(response.json(), DeliveryMethod.EMAIL)
245+
127246
def update_user_phone(
128247
self,
129248
method: DeliveryMethod,
@@ -144,13 +263,50 @@ def update_user_phone(
144263
Auth.validate_phone(method, phone)
145264

146265
body = MagicLink._compose_update_user_phone_body(
147-
login_id, phone, add_to_login_ids, on_merge_use_existing,
148-
template_options, template_id, provider_id
266+
login_id,
267+
phone,
268+
add_to_login_ids,
269+
on_merge_use_existing,
270+
template_options,
271+
template_id,
272+
provider_id,
149273
)
150274
uri = EndpointsV1.update_user_phone_magiclink_path
151275
response = self._auth.do_post(uri, body, None, refresh_token)
152276
return Auth.extract_masked_address(response.json(), DeliveryMethod.SMS)
153277

278+
async def update_user_phone_async(
279+
self,
280+
method: DeliveryMethod,
281+
login_id: str,
282+
phone: str,
283+
refresh_token: str,
284+
add_to_login_ids: bool = False,
285+
on_merge_use_existing: bool = False,
286+
template_options: dict | None = None,
287+
template_id: str | None = None,
288+
provider_id: str | None = None,
289+
) -> str:
290+
if not login_id:
291+
raise AuthException(
292+
400, ERROR_TYPE_INVALID_ARGUMENT, "Identifier cannot be empty"
293+
)
294+
295+
Auth.validate_phone(method, phone)
296+
297+
body = MagicLink._compose_update_user_phone_body(
298+
login_id,
299+
phone,
300+
add_to_login_ids,
301+
on_merge_use_existing,
302+
template_options,
303+
template_id,
304+
provider_id,
305+
)
306+
uri = EndpointsV1.update_user_phone_magiclink_path
307+
response = await self._auth.do_post_async(uri, body, None, refresh_token)
308+
return Auth.extract_masked_address(response.json(), DeliveryMethod.SMS)
309+
154310
@staticmethod
155311
def _compose_signin_url(method: DeliveryMethod) -> str:
156312
return Auth.compose_url(EndpointsV1.sign_in_auth_magiclink_path, method)

0 commit comments

Comments
 (0)