diff --git a/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeCaptchaToExpectedPayload_GivenOptions.verified.txt b/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeCaptchaToExpectedPayload_GivenOptions.verified.txt
new file mode 100644
index 00000000..7027963f
--- /dev/null
+++ b/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeCaptchaToExpectedPayload_GivenOptions.verified.txt
@@ -0,0 +1 @@
+{"type":"signup","email":"user@supabase.com","gotrue_meta_security":{"captcha_token":"captcha-token"}}
\ No newline at end of file
diff --git a/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeToExpectedPayload_GivenEmailChangeType.verified.txt b/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeToExpectedPayload_GivenEmailChangeType.verified.txt
new file mode 100644
index 00000000..f05b5da4
--- /dev/null
+++ b/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeToExpectedPayload_GivenEmailChangeType.verified.txt
@@ -0,0 +1 @@
+{"type":"email_change","email":"user@supabase.com"}
\ No newline at end of file
diff --git a/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeToExpectedPayload_GivenPhoneChangeType.verified.txt b/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeToExpectedPayload_GivenPhoneChangeType.verified.txt
new file mode 100644
index 00000000..bfbfa256
--- /dev/null
+++ b/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeToExpectedPayload_GivenPhoneChangeType.verified.txt
@@ -0,0 +1 @@
+{"type":"phone_change","phone":"+5544998989898"}
\ No newline at end of file
diff --git a/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeToExpectedPayload_GivenSignUpType.verified.txt b/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeToExpectedPayload_GivenSignUpType.verified.txt
new file mode 100644
index 00000000..16a7bbcd
--- /dev/null
+++ b/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeToExpectedPayload_GivenSignUpType.verified.txt
@@ -0,0 +1 @@
+{"type":"signup","email":"user@supabase.com"}
\ No newline at end of file
diff --git a/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeToExpectedPayload_GivenSmsType.verified.txt b/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeToExpectedPayload_GivenSmsType.verified.txt
new file mode 100644
index 00000000..6d7aaab2
--- /dev/null
+++ b/packages/Gotrue/Gotrue.Tests/Authentication/Data/ResendParametersContractTests.ResendRequest_ShouldSerializeToExpectedPayload_GivenSmsType.verified.txt
@@ -0,0 +1 @@
+{"type":"sms","phone":"+5544998989898"}
\ No newline at end of file
diff --git a/packages/Gotrue/Gotrue.Tests/Authentication/ResendParametersContractTests.cs b/packages/Gotrue/Gotrue.Tests/Authentication/ResendParametersContractTests.cs
new file mode 100644
index 00000000..999bb803
--- /dev/null
+++ b/packages/Gotrue/Gotrue.Tests/Authentication/ResendParametersContractTests.cs
@@ -0,0 +1,89 @@
+using System.Threading.Tasks;
+using Gotrue.Tests.Support;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Supabase.Gotrue.Resend;
+
+namespace Gotrue.Tests.Authentication;
+
+///
+/// Pins the exact bytes the resend requests put on the wire, including the type enum mappings
+/// (signup, sms, phone_change, email_change) and whether the target is sent
+/// as email or phone.
+///
+[TestClass]
+[TestCategory("Contract")]
+public class ResendParametersContractTests : RequestApprovalFixture
+{
+ [TestMethod]
+ public async Task ResendRequest_ShouldSerializeToExpectedPayload_GivenSignUpType()
+ {
+ const string email = "user@supabase.com";
+ var resend = new ResendParameters(
+ type: ResendType.SignUp,
+ email: email,
+ phone: null,
+ options: null
+ );
+ await this.Api.Resend(resend);
+
+ await this.Verify(this.EmittedRequestBody).UseDirectory("Data");
+ }
+
+ [TestMethod]
+ public async Task ResendRequest_ShouldSerializeToExpectedPayload_GivenEmailChangeType()
+ {
+ const string email = "user@supabase.com";
+ var resend = new ResendParameters(
+ type: ResendType.EmailChange,
+ email: email,
+ phone: null,
+ options: null
+ );
+ await this.Api.Resend(resend);
+
+ await this.Verify(this.EmittedRequestBody).UseDirectory("Data");
+ }
+
+ [TestMethod]
+ public async Task ResendRequest_ShouldSerializeToExpectedPayload_GivenPhoneChangeType()
+ {
+ var resend = new ResendParameters(
+ type: ResendType.PhoneChange,
+ email: null,
+ phone: "+5544998989898",
+ options: null
+ );
+ await this.Api.Resend(resend);
+
+ await this.Verify(this.EmittedRequestBody).UseDirectory("Data");
+ }
+
+ [TestMethod]
+ public async Task ResendRequest_ShouldSerializeToExpectedPayload_GivenSmsType()
+ {
+ var resend = new ResendParameters(
+ type: ResendType.Sms,
+ email: null,
+ phone: "+5544998989898",
+ options: null
+ );
+ await this.Api.Resend(resend);
+
+ await this.Verify(this.EmittedRequestBody).UseDirectory("Data");
+ }
+
+ [TestMethod]
+ public async Task ResendRequest_ShouldSerializeCaptchaToExpectedPayload_GivenOptions()
+ {
+ var resend = new ResendParameters(
+ type: ResendType.SignUp,
+ email: "user@supabase.com",
+ phone: null,
+ options: new ResendOptions(captchaToken: "captcha-token", emailRedirectTo: null)
+ );
+
+ await this.Api.Resend(resend);
+
+ await this.Verify(this.EmittedRequestBody).UseDirectory("Data");
+ }
+}
diff --git a/packages/Gotrue/Gotrue.Tests/Authentication/ResendParametersTests.cs b/packages/Gotrue/Gotrue.Tests/Authentication/ResendParametersTests.cs
new file mode 100644
index 00000000..a92762c3
--- /dev/null
+++ b/packages/Gotrue/Gotrue.Tests/Authentication/ResendParametersTests.cs
@@ -0,0 +1,143 @@
+using System.Net;
+using System.Threading.Tasks;
+using Gotrue.Tests.Support;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Supabase.Gotrue.Exceptions;
+using Supabase.Gotrue.Resend;
+using static Gotrue.Tests.TestUtils;
+
+namespace Gotrue.Tests.Authentication;
+
+[TestClass]
+[TestCategory("E2E")]
+public class ResendParametersTests : AuthClientFixture
+{
+ [TestMethod]
+ public async Task Resend_ShouldRequestConfirmationCode_GivenSignUpType()
+ {
+ var email = RandomEmail();
+ var resend = new ResendParameters(
+ type: ResendType.SignUp,
+ email: email,
+ phone: null,
+ options: null
+ );
+ var response = await this.Client.Resend(resend);
+
+ Assert.IsNotNull(response);
+ Assert.AreEqual(HttpStatusCode.OK, response.ResponseMessage?.StatusCode);
+ }
+
+ [TestMethod]
+ public async Task Resend_ShouldRequestConfirmationCode_GivenSmsType()
+ {
+ var resend = new ResendParameters(
+ type: ResendType.Sms,
+ email: null,
+ phone: "5544989899898",
+ options: null
+ );
+ var response = await this.Client.Resend(resend);
+
+ Assert.IsNotNull(response);
+ Assert.AreEqual(HttpStatusCode.OK, response.ResponseMessage?.StatusCode);
+ }
+
+ [TestMethod]
+ public async Task Resend_ShouldRequestConfirmationCode_GivenPhoneChangeType()
+ {
+ var resend = new ResendParameters(
+ type: ResendType.PhoneChange,
+ email: null,
+ phone: "5544989899898",
+ options: null
+ );
+ var response = await this.Client.Resend(resend);
+
+ Assert.IsNotNull(response);
+ Assert.AreEqual(HttpStatusCode.OK, response.ResponseMessage?.StatusCode);
+ }
+
+ [TestMethod]
+ public async Task Resend_ShouldRequestConfirmationCode_GivenEmailChangeType()
+ {
+ var resend = new ResendParameters(
+ type: ResendType.EmailChange,
+ email: RandomEmail(),
+ phone: null,
+ options: null
+ );
+ var response = await this.Client.Resend(resend);
+
+ Assert.IsNotNull(response);
+ Assert.AreEqual(HttpStatusCode.OK, response.ResponseMessage?.StatusCode);
+ }
+
+ [TestMethod]
+ public async Task Resend_ShouldThrowErrorWhenParameterAreInvalid_GivenPhoneForTypeEmail()
+ {
+ var resend = new ResendParameters(
+ type: ResendType.EmailChange,
+ email: null,
+ phone: "5544989899898",
+ options: null
+ );
+
+ var action = async () => await this.Client.Resend(resend);
+
+ var exception = await Assert.ThrowsAsync(action);
+ Assert.Contains("Missing email address or phone number", exception.Message);
+ Assert.Contains("400", exception.Message);
+ }
+
+ [TestMethod]
+ public async Task Resend_ShouldThrowErrorWhenParameterAreInvalid_GivenEmailForTypePhone()
+ {
+ var resend = new ResendParameters(
+ type: ResendType.Sms,
+ email: RandomEmail(),
+ phone: null,
+ options: null
+ );
+
+ var action = async () => await this.Client.Resend(resend);
+
+ var exception = await Assert.ThrowsAsync(action);
+ Assert.Contains("Type provided requires a phone number", exception.Message);
+ Assert.Contains("400", exception.Message);
+ }
+
+ [TestMethod]
+ public async Task Resend_ShouldThrowErrorWhenParameterAreInvalid_GivenNothingForTypeEmail()
+ {
+ var resend = new ResendParameters(
+ type: ResendType.EmailChange,
+ email: null,
+ phone: null,
+ options: null
+ );
+
+ var action = async () => await this.Client.Resend(resend);
+
+ var exception = await Assert.ThrowsAsync(action);
+ Assert.Contains("Missing email address or phone number", exception.Message);
+ Assert.Contains("400", exception.Message);
+ }
+
+ [TestMethod]
+ public async Task Resend_ShouldThrowErrorWhenParameterAreInvalid_GivenNothingForTypePhone()
+ {
+ var resend = new ResendParameters(
+ type: ResendType.Sms,
+ email: null,
+ phone: null,
+ options: null
+ );
+
+ var action = async () => await this.Client.Resend(resend);
+
+ var exception = await Assert.ThrowsAsync(action);
+ Assert.Contains("Type provided requires a phone number", exception.Message);
+ Assert.Contains("400", exception.Message);
+ }
+}
diff --git a/packages/Gotrue/Gotrue/Api.cs b/packages/Gotrue/Gotrue/Api.cs
index ed3e25f2..e0daa3bc 100644
--- a/packages/Gotrue/Gotrue/Api.cs
+++ b/packages/Gotrue/Gotrue/Api.cs
@@ -13,6 +13,7 @@
using Supabase.Gotrue.Exceptions;
using Supabase.Gotrue.Interfaces;
using Supabase.Gotrue.Mfa;
+using Supabase.Gotrue.Resend;
using Supabase.Gotrue.Responses;
using static Supabase.Gotrue.Constants;
@@ -889,4 +890,22 @@ public Task GenerateLink(string jwt, GenerateLinkOptions options)
return this.MakeRequestAsync(HttpMethod.Post, $"{this.Url}/token?grant_type=refresh_token", data, this.Headers.MergeLeft(headers));
}
+
+ ///
+ /// Resends a confirmation code to a user's email or phone.
+ ///
+ ///
+ /// BaseResponse
+ public Task Resend(ResendParameters resendParameters)
+ {
+ var body = resendParameters.ToDictionary();
+ var url = resendParameters.ApplyRedirectTo(this.Url);
+
+ return this.MakeRequestAsync(
+ HttpMethod.Post,
+ url,
+ body,
+ this.Headers
+ );
+ }
}
diff --git a/packages/Gotrue/Gotrue/Client.cs b/packages/Gotrue/Gotrue/Client.cs
index 8ee751fa..809ad973 100644
--- a/packages/Gotrue/Gotrue/Client.cs
+++ b/packages/Gotrue/Gotrue/Client.cs
@@ -14,6 +14,8 @@
using Supabase.Gotrue.Exceptions;
using Supabase.Gotrue.Interfaces;
using Supabase.Gotrue.Mfa;
+using Supabase.Gotrue.Resend;
+using Supabase.Gotrue.Responses;
using static Supabase.Gotrue.Constants;
using static Supabase.Gotrue.Constants.AuthState;
using static Supabase.Gotrue.Exceptions.FailureHint.Reason;
@@ -983,6 +985,9 @@ private void ApplyLoadedSession(Session? before, Session? loaded)
///
public void Shutdown() => this.NotifyAuthStateChange(AuthState.Shutdown);
+ ///
+ public Task Resend(ResendParameters resendParameters) => this.api.Resend(resendParameters);
+
///
public async Task Enroll(MfaEnrollParams mfaEnrollParams)
{
diff --git a/packages/Gotrue/Gotrue/Constants.cs b/packages/Gotrue/Gotrue/Constants.cs
index fac3e04b..5b534b36 100644
--- a/packages/Gotrue/Gotrue/Constants.cs
+++ b/packages/Gotrue/Gotrue/Constants.cs
@@ -1,167 +1,197 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
using Supabase.Core.Attributes;
#pragma warning disable CS1591
-namespace Supabase.Gotrue
+namespace Supabase.Gotrue;
+
+///
+/// Constants used throughout the Gotrue Client
+///
+public static class Constants
{
- ///
- /// Constants used throughout the Gotrue Client
- ///
- public static class Constants
- {
- ///
- /// URL for the Gotrue server. Defaults to localhost:9999.
- ///
- public const string GOTRUE_URL = "http://localhost:9999";
- public const string AUDIENCE = "";
- public const int EXPIRY_MARGIN = 60 * 1000;
- public const string STORAGE_KEY = "supabase.auth.token";
- public static readonly Dictionary CookieOptions = new Dictionary
- {
- { "name", "sb:token" },
- { "lifetime", 60 * 60 * 8 },
- { "domain", "" },
- { "path", "/" },
- { "sameSite", "lax" }
- };
-
- public enum SortOrder
- {
- [MapTo("asc")]
- Ascending,
- [MapTo("desc")]
- Descending
- }
-
- public enum MobileOtpType
- {
- [MapTo("sms")]
- SMS,
- [MapTo("phone_change")]
- PhoneChange
- }
-
- public enum EmailOtpType
- {
- [MapTo("signup")]
- Signup,
- [MapTo("invite")]
- Invite,
- [MapTo("magiclink")]
- MagicLink,
- [MapTo("recovery")]
- Recovery,
- [MapTo("email_change")]
- EmailChange,
- [MapTo("email")]
- Email
- }
-
- ///
- /// Providers available to Supabase
- /// Ref: https://supabase.github.io/gotrue-js/modules.html#Provider
- ///
- public enum Provider
- {
- [MapTo("anonymous_users")]
- AnonymousUsers,
- [MapTo("apple")]
- Apple,
- [MapTo("azure")]
- Azure,
- [MapTo("bitbucket")]
- Bitbucket,
- [MapTo("discord")]
- Discord,
- [MapTo("facebook")]
- Facebook,
- [MapTo("figma")]
- Figma,
- [MapTo("fly")]
- Fly,
- [MapTo("github")]
- Github,
- [MapTo("gitlab")]
- Gitlab,
- [MapTo("google")]
- Google,
- [MapTo("kakao")]
- Kakao,
- [MapTo("keycloak")]
- KeyCloak,
- [MapTo("linkedin")]
- LinkedIn,
- [MapTo("linkedin_oidc")]
- LinkedInOIDC,
- [MapTo("notion")]
- Notion,
- [MapTo("slack")]
- Slack,
- [MapTo("spotify")]
- Spotify,
- [MapTo("twitch")]
- Twitch,
- [MapTo("twitter")]
- Twitter,
- [MapTo("workos")]
- WorkOS,
- [MapTo("zoom")]
- Zoom
- }
-
- ///
- /// States that the Auth Client will raise events for.
- ///
- public enum AuthState
- {
- SignedIn,
- SignedOut,
- UserUpdated,
- PasswordRecovery,
- TokenRefreshed,
- Shutdown,
- MfaChallengeVerified
- }
-
- ///
- /// Specifies the functionality expected from the `SignIn` method
- ///
- public enum SignInType
- {
- Email,
- Phone,
- RefreshToken
- }
-
- ///
- /// Represents an OAuth Flow type
- ///
- public enum OAuthFlowType
- {
- [MapTo("implicit")]
- Implicit,
- [MapTo("pkce")]
- PKCE
- }
-
- ///
- /// Specifies the functionality expected from the `SignUp` method
- ///
- public enum SignUpType
- {
- Email,
- Phone
- }
-
- public enum SignOutScope
- {
- [MapTo("global")]
- Global,
- [MapTo("local")]
- Local,
- [MapTo("others")]
- Others
- }
+ ///
+ /// URL for the Gotrue server. Defaults to localhost:9999.
+ ///
+ public const string GOTRUE_URL = "http://localhost:9999";
+ public const string AUDIENCE = "";
+ public const int EXPIRY_MARGIN = 60 * 1000;
+ public const string STORAGE_KEY = "supabase.auth.token";
+ public static readonly Dictionary CookieOptions = new Dictionary
+ {
+ { "name", "sb:token" },
+ { "lifetime", 60 * 60 * 8 },
+ { "domain", "" },
+ { "path", "/" },
+ { "sameSite", "lax" },
+ };
+
+ public enum SortOrder
+ {
+ [MapTo("asc")]
+ Ascending,
+
+ [MapTo("desc")]
+ Descending,
+ }
+
+ public enum MobileOtpType
+ {
+ [MapTo("sms")]
+ SMS,
+
+ [MapTo("phone_change")]
+ PhoneChange,
+ }
+
+ public enum EmailOtpType
+ {
+ [MapTo("signup")]
+ Signup,
+
+ [MapTo("invite")]
+ Invite,
+
+ [MapTo("magiclink")]
+ MagicLink,
+
+ [MapTo("recovery")]
+ Recovery,
+
+ [MapTo("email_change")]
+ EmailChange,
+
+ [MapTo("email")]
+ Email,
+ }
+
+ ///
+ /// Providers available to Supabase
+ /// Ref: https://supabase.github.io/gotrue-js/modules.html#Provider
+ ///
+ public enum Provider
+ {
+ [MapTo("anonymous_users")]
+ AnonymousUsers,
+
+ [MapTo("apple")]
+ Apple,
+
+ [MapTo("azure")]
+ Azure,
+
+ [MapTo("bitbucket")]
+ Bitbucket,
+
+ [MapTo("discord")]
+ Discord,
+
+ [MapTo("facebook")]
+ Facebook,
+
+ [MapTo("figma")]
+ Figma,
+
+ [MapTo("fly")]
+ Fly,
+
+ [MapTo("github")]
+ Github,
+
+ [MapTo("gitlab")]
+ Gitlab,
+
+ [MapTo("google")]
+ Google,
+
+ [MapTo("kakao")]
+ Kakao,
+
+ [MapTo("keycloak")]
+ KeyCloak,
+
+ [MapTo("linkedin")]
+ LinkedIn,
+
+ [MapTo("linkedin_oidc")]
+ LinkedInOIDC,
+
+ [MapTo("notion")]
+ Notion,
+
+ [MapTo("slack")]
+ Slack,
+
+ [MapTo("spotify")]
+ Spotify,
+
+ [MapTo("twitch")]
+ Twitch,
+
+ [MapTo("twitter")]
+ Twitter,
+
+ [MapTo("workos")]
+ WorkOS,
+
+ [MapTo("zoom")]
+ Zoom,
+ }
+
+ ///
+ /// States that the Auth Client will raise events for.
+ ///
+ public enum AuthState
+ {
+ SignedIn,
+ SignedOut,
+ UserUpdated,
+ PasswordRecovery,
+ TokenRefreshed,
+ Shutdown,
+ MfaChallengeVerified,
+ }
+
+ ///
+ /// Specifies the functionality expected from the `SignIn` method
+ ///
+ public enum SignInType
+ {
+ Email,
+ Phone,
+ RefreshToken,
+ }
+
+ ///
+ /// Represents an OAuth Flow type
+ ///
+ public enum OAuthFlowType
+ {
+ [MapTo("implicit")]
+ Implicit,
+
+ [MapTo("pkce")]
+ PKCE,
+ }
+
+ ///
+ /// Specifies the functionality expected from the `SignUp` method
+ ///
+ public enum SignUpType
+ {
+ Email,
+ Phone,
+ }
+
+ public enum SignOutScope
+ {
+ [MapTo("global")]
+ Global,
+
+ [MapTo("local")]
+ Local,
+
+ [MapTo("others")]
+ Others,
}
}
diff --git a/packages/Gotrue/Gotrue/Interfaces/IGotrueApi.cs b/packages/Gotrue/Gotrue/Interfaces/IGotrueApi.cs
index de61f5d0..b3b0fa8b 100644
--- a/packages/Gotrue/Gotrue/Interfaces/IGotrueApi.cs
+++ b/packages/Gotrue/Gotrue/Interfaces/IGotrueApi.cs
@@ -4,6 +4,7 @@
using Supabase.Core.Interfaces;
using Supabase.Gotrue.Claims;
using Supabase.Gotrue.Mfa;
+using Supabase.Gotrue.Resend;
using Supabase.Gotrue.Responses;
using static Supabase.Gotrue.Constants;
@@ -87,4 +88,11 @@ public interface IGotrueApi : IGettableHeaders
/// Identity to be unlinked
///
Task UnlinkIdentity(string token, UserIdentity userIdentity);
+
+ ///
+ /// Resends a confirmation code to a user's email or phone.
+ ///
+ ///
+ ///
+ Task Resend(ResendParameters resendParameters);
}
diff --git a/packages/Gotrue/Gotrue/Interfaces/IGotrueClient.cs b/packages/Gotrue/Gotrue/Interfaces/IGotrueClient.cs
index 8c10acc1..e749a13f 100644
--- a/packages/Gotrue/Gotrue/Interfaces/IGotrueClient.cs
+++ b/packages/Gotrue/Gotrue/Interfaces/IGotrueClient.cs
@@ -7,6 +7,8 @@
using Supabase.Gotrue.Claims;
using Supabase.Gotrue.Exceptions;
using Supabase.Gotrue.Mfa;
+using Supabase.Gotrue.Resend;
+using Supabase.Gotrue.Responses;
using static Supabase.Gotrue.Constants;
#endregion
@@ -548,6 +550,13 @@ public interface IGotrueClient : IGettableHeaders
/// The refresh token to exchange for a new session.
Task RefreshToken(string accessToken, string refreshToken);
+ ///
+ /// Resends a confirmation code to a user's email or phone.
+ ///
+ ///
+ ///
+ Task Resend(ResendParameters resendParameters);
+
#region MFA
///
diff --git a/packages/Gotrue/Gotrue/PublicAPI.Unshipped.txt b/packages/Gotrue/Gotrue/PublicAPI.Unshipped.txt
index ed2037b9..362ae531 100644
--- a/packages/Gotrue/Gotrue/PublicAPI.Unshipped.txt
+++ b/packages/Gotrue/Gotrue/PublicAPI.Unshipped.txt
@@ -31,6 +31,7 @@ static Supabase.Gotrue.Claims.JwtHeader.operator !=(Supabase.Gotrue.Claims.JwtHe
static Supabase.Gotrue.Claims.JwtHeader.operator ==(Supabase.Gotrue.Claims.JwtHeader? left, Supabase.Gotrue.Claims.JwtHeader? right) -> bool
Supabase.Gotrue.Api.GetJwksAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
Supabase.Gotrue.Api.GetUserAsync(string! jwt, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
+Supabase.Gotrue.Api.Resend(Supabase.Gotrue.Resend.ResendParameters! resendParameters) -> System.Threading.Tasks.Task!
Supabase.Gotrue.Claims.GetClaimsOptions
Supabase.Gotrue.Claims.GetClaimsOptions.$() -> Supabase.Gotrue.Claims.GetClaimsOptions!
Supabase.Gotrue.Claims.GetClaimsOptions.AllowExpired.get -> bool
@@ -110,10 +111,29 @@ Supabase.Gotrue.Claims.JwtHeader.Kid.init -> void
Supabase.Gotrue.Claims.JwtHeader.Typ.get -> string?
Supabase.Gotrue.Claims.JwtHeader.Typ.init -> void
Supabase.Gotrue.Client.GetClaimsAsync(string? jwt = null, Supabase.Gotrue.Claims.GetClaimsOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
+Supabase.Gotrue.Client.Resend(Supabase.Gotrue.Resend.ResendParameters! resendParameters) -> System.Threading.Tasks.Task!
Supabase.Gotrue.Exceptions.FailureHint.Reason.InvalidJwt = 22 -> Supabase.Gotrue.Exceptions.FailureHint.Reason
Supabase.Gotrue.Interfaces.IGotrueApi.GetJwksAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
Supabase.Gotrue.Interfaces.IGotrueApi.GetUserAsync(string! jwt, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
+Supabase.Gotrue.Interfaces.IGotrueApi.Resend(Supabase.Gotrue.Resend.ResendParameters! resendParameters) -> System.Threading.Tasks.Task!
Supabase.Gotrue.Interfaces.IGotrueClient.GetClaimsAsync(string? jwt = null, Supabase.Gotrue.Claims.GetClaimsOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task!
+Supabase.Gotrue.Interfaces.IGotrueClient.Resend(Supabase.Gotrue.Resend.ResendParameters! resendParameters) -> System.Threading.Tasks.Task!
+Supabase.Gotrue.Resend.ResendOptions
+Supabase.Gotrue.Resend.ResendOptions.CaptchaToken.get -> string?
+Supabase.Gotrue.Resend.ResendOptions.EmailRedirectTo.get -> string?
+Supabase.Gotrue.Resend.ResendOptions.ResendOptions(string? captchaToken, string? emailRedirectTo) -> void
+Supabase.Gotrue.Resend.ResendParameters
+Supabase.Gotrue.Resend.ResendParameters.Email.get -> string?
+Supabase.Gotrue.Resend.ResendParameters.Options.get -> Supabase.Gotrue.Resend.ResendOptions?
+Supabase.Gotrue.Resend.ResendParameters.Phone.get -> string?
+Supabase.Gotrue.Resend.ResendParameters.ResendParameters(Supabase.Gotrue.Resend.ResendType type, string? email, string? phone, Supabase.Gotrue.Resend.ResendOptions? options) -> void
+Supabase.Gotrue.Resend.ResendParameters.ToDictionary() -> System.Collections.Generic.Dictionary!
+Supabase.Gotrue.Resend.ResendParameters.Type.get -> Supabase.Gotrue.Resend.ResendType
+Supabase.Gotrue.Resend.ResendType
+Supabase.Gotrue.Resend.ResendType.EmailChange = 3 -> Supabase.Gotrue.Resend.ResendType
+Supabase.Gotrue.Resend.ResendType.PhoneChange = 2 -> Supabase.Gotrue.Resend.ResendType
+Supabase.Gotrue.Resend.ResendType.SignUp = 0 -> Supabase.Gotrue.Resend.ResendType
+Supabase.Gotrue.Resend.ResendType.Sms = 1 -> Supabase.Gotrue.Resend.ResendType
Supabase.Gotrue.SignUpOptions.CaptchaToken.get -> string?
Supabase.Gotrue.SignUpOptions.CaptchaToken.set -> void
Supabase.Gotrue.Api.SignInWithEmail(string! email, string! password, Supabase.Gotrue.SignInWithPasswordOptions! options) -> System.Threading.Tasks.Task!
diff --git a/packages/Gotrue/Gotrue/Resend/ResendOptions.cs b/packages/Gotrue/Gotrue/Resend/ResendOptions.cs
new file mode 100644
index 00000000..b9f21460
--- /dev/null
+++ b/packages/Gotrue/Gotrue/Resend/ResendOptions.cs
@@ -0,0 +1,28 @@
+namespace Supabase.Gotrue.Resend;
+
+///
+/// Represents optional parameters used in the Resend API. These parameters provide
+/// additional customization for the resend operation, such as including a CAPTCHA
+/// token or specifying a redirection URL after email confirmation.
+///
+public class ResendOptions
+{
+ ///
+ /// Verification token received when the user completes the captcha on the site.
+ ///
+ public string? CaptchaToken { get; }
+
+ ///
+ /// A URL or mobile address to send the user to after they are confirmed.
+ ///
+ public string? EmailRedirectTo { get; }
+
+ ///
+ /// Represents optional parameters for a resend operation in the Resend API.
+ ///
+ public ResendOptions(string? captchaToken, string? emailRedirectTo)
+ {
+ this.CaptchaToken = captchaToken;
+ this.EmailRedirectTo = emailRedirectTo;
+ }
+}
diff --git a/packages/Gotrue/Gotrue/Resend/ResendParameters.cs b/packages/Gotrue/Gotrue/Resend/ResendParameters.cs
new file mode 100644
index 00000000..2ed94893
--- /dev/null
+++ b/packages/Gotrue/Gotrue/Resend/ResendParameters.cs
@@ -0,0 +1,106 @@
+using System.Collections.Generic;
+
+namespace Supabase.Gotrue.Resend;
+
+///
+/// Parameters for the Resend API.
+///
+public class ResendParameters
+{
+ ///
+ /// The email address to resend to.
+ ///
+ public string? Email { get; }
+
+ ///
+ /// The phone number to resend to.
+ ///
+ public string? Phone { get; }
+
+ ///
+ /// The type of resend.
+ ///
+ public ResendType Type { get; }
+
+ ///
+ /// Additional options to customize the behavior of the Resend API.
+ /// Provides support for features such as CAPTCHA tokens and email redirection.
+ ///
+ public ResendOptions? Options { get; }
+
+ ///
+ /// Represents the parameters required for a resend operation, such as resending a confirmation email
+ /// or a verification SMS, depending on the specified type.
+ ///
+ public ResendParameters(ResendType type, string? email, string? phone, ResendOptions? options)
+ {
+ this.Type = type;
+ this.Email = email;
+ this.Phone = phone;
+ this.Options = options;
+ }
+
+ ///
+ /// Converts the resend parameters to a dictionary format, including the type, email, phone,
+ /// and any additional options, for use in API requests.
+ ///
+ ///
+ /// A dictionary containing the key-value pairs representing the resend parameters.
+ ///
+ public Dictionary ToDictionary()
+ {
+ var body = new Dictionary
+ {
+ { "type", Core.Helpers.GetMappedToAttr(this.Type).Mapping },
+ };
+
+ body = this.AddEmailAndTokenField(body);
+ body = this.AddPhoneField(body);
+
+ return body;
+ }
+
+ internal string ApplyRedirectTo(string url)
+ {
+ var newUrl = $"{url}/resend";
+ if (!this.IsEmail())
+ return newUrl;
+
+ if (!string.IsNullOrWhiteSpace(this.Options?.EmailRedirectTo))
+ newUrl = $"{url}/resend?redirect_to={this.Options.EmailRedirectTo}";
+
+ return newUrl;
+ }
+
+ private bool IsEmail() => this.Type is ResendType.EmailChange or ResendType.SignUp;
+
+ private Dictionary AddEmailAndTokenField(Dictionary parameter)
+ {
+ if (!this.IsEmail())
+ return parameter;
+
+ var body = new Dictionary(parameter);
+ if (!string.IsNullOrWhiteSpace(this.Email))
+ body.Add("email", this.Email);
+
+ if (!string.IsNullOrWhiteSpace(this.Options?.CaptchaToken))
+ body.Add(
+ "gotrue_meta_security",
+ new Dictionary { { "captcha_token", this.Options.CaptchaToken } }
+ );
+
+ return body;
+ }
+
+ private Dictionary AddPhoneField(Dictionary parameter)
+ {
+ if (this.IsEmail())
+ return parameter;
+
+ var body = new Dictionary(parameter);
+ if (!string.IsNullOrWhiteSpace(this.Phone))
+ body.Add("phone", this.Phone);
+
+ return body;
+ }
+}
diff --git a/packages/Gotrue/Gotrue/Resend/ResendType.cs b/packages/Gotrue/Gotrue/Resend/ResendType.cs
new file mode 100644
index 00000000..b57fe572
--- /dev/null
+++ b/packages/Gotrue/Gotrue/Resend/ResendType.cs
@@ -0,0 +1,25 @@
+using Supabase.Core.Attributes;
+
+namespace Supabase.Gotrue.Resend;
+
+///
+/// The type of resend.
+///
+public enum ResendType
+{
+ /// Signup resend.
+ [MapTo("signup")]
+ SignUp,
+
+ /// SMS resend.
+ [MapTo("sms")]
+ Sms,
+
+ /// Phone change resend.
+ [MapTo("phone_change")]
+ PhoneChange,
+
+ /// Email change resend.
+ [MapTo("email_change")]
+ EmailChange,
+}