diff --git a/supabase_auth/_async/gotrue_client.py b/supabase_auth/_async/gotrue_client.py index 35536993..90013a9e 100644 --- a/supabase_auth/_async/gotrue_client.py +++ b/supabase_auth/_async/gotrue_client.py @@ -61,6 +61,7 @@ OAuthResponse, Options, Provider, + ResendCredentials, Session, SignInAnonymouslyCredentials, SignInWithIdTokenCredentials, @@ -519,6 +520,41 @@ async def sign_in_with_otp( "You must provide either an email or phone number" ) + async def resend( + self, + credentials: ResendCredentials, + ) -> AuthOtpResponse: + """ + Resends an existing signup confirmation email, email change email, SMS OTP or phone change OTP. + """ + email = credentials.get("email") + phone = credentials.get("phone") + type = credentials.get("type") + options = credentials.get("options", {}) + email_redirect_to = options.get("email_redirect_to") + captcha_token = options.get("captcha_token") + body = { + "type": type, + "gotrue_meta_security": { + "captcha_token": captcha_token, + }, + } + + if email is None and phone is None: + raise AuthInvalidCredentialsError( + "You must provide either an email or phone number" + ) + + body.update({"email": email} if email else {"phone": phone}) + + return await self._request( + "POST", + "resend", + body=body, + redirect_to=email_redirect_to if email else None, + xform=parse_auth_otp_response, + ) + async def verify_otp(self, params: VerifyOtpParams) -> AuthResponse: """ Log in a user given a User supplied OTP received via mobile. diff --git a/supabase_auth/_sync/gotrue_client.py b/supabase_auth/_sync/gotrue_client.py index cd26728b..16ee3e65 100644 --- a/supabase_auth/_sync/gotrue_client.py +++ b/supabase_auth/_sync/gotrue_client.py @@ -61,6 +61,7 @@ OAuthResponse, Options, Provider, + ResendCredentials, Session, SignInAnonymouslyCredentials, SignInWithIdTokenCredentials, @@ -513,6 +514,41 @@ def sign_in_with_otp( "You must provide either an email or phone number" ) + def resend( + self, + credentials: ResendCredentials, + ) -> AuthOtpResponse: + """ + Resends an existing signup confirmation email, email change email, SMS OTP or phone change OTP. + """ + email = credentials.get("email") + phone = credentials.get("phone") + type = credentials.get("type") + options = credentials.get("options", {}) + email_redirect_to = options.get("email_redirect_to") + captcha_token = options.get("captcha_token") + body = { + "type": type, + "gotrue_meta_security": { + "captcha_token": captcha_token, + }, + } + + if email is None and phone is None: + raise AuthInvalidCredentialsError( + "You must provide either an email or phone number" + ) + + body.update({"email": email} if email else {"phone": phone}) + + return self._request( + "POST", + "resend", + body=body, + redirect_to=email_redirect_to if email else None, + xform=parse_auth_otp_response, + ) + def verify_otp(self, params: VerifyOtpParams) -> AuthResponse: """ Log in a user given a User supplied OTP received via mobile. diff --git a/supabase_auth/types.py b/supabase_auth/types.py index 5db169b0..5ecd23cf 100644 --- a/supabase_auth/types.py +++ b/supabase_auth/types.py @@ -376,6 +376,30 @@ class SignInWithPhoneAndPasswordlessCredentials(TypedDict): ] +class ResendEmailCredentialsOptions(TypedDict): + email_redirect_to: NotRequired[str] + captcha_token: NotRequired[str] + + +class ResendEmailCredentials(TypedDict): + type: Literal["signup", "email_change"] + email: str + options: NotRequired[ResendEmailCredentialsOptions] + + +class ResendPhoneCredentialsOptions(TypedDict): + captcha_token: NotRequired[str] + + +class ResendPhoneCredentials(TypedDict): + type: Literal["sms", "phone_change"] + phone: str + options: NotRequired[ResendPhoneCredentialsOptions] + + +ResendCredentials = Union[ResendEmailCredentials, ResendPhoneCredentials] + + class SignInWithOAuthCredentialsOptions(TypedDict): redirect_to: NotRequired[str] scopes: NotRequired[str]