diff --git a/Thirdweb.Console/Program.cs b/Thirdweb.Console/Program.cs
index a9737bc..73a83e6 100644
--- a/Thirdweb.Console/Program.cs
+++ b/Thirdweb.Console/Program.cs
@@ -325,6 +325,18 @@
#endregion
+#region Backend Wallet Auth
+
+// var inAppWalletBackend = await InAppWallet.Create(client: client, authProvider: AuthProvider.Backend, walletSecret: "very-secret");
+// if (!await inAppWalletBackend.IsConnected())
+// {
+// _ = await inAppWalletBackend.LoginWithBackend();
+// }
+// var inAppWalletBackendAddress = await inAppWalletBackend.GetAddress();
+// Console.WriteLine($"InAppWallet Backend address: {inAppWalletBackendAddress}");
+
+#endregion
+
#region Account Linking
// var inAppWalletMain = await InAppWallet.Create(client: client, authProvider: AuthProvider.Telegram);
diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs
index 8918153..622b5b5 100644
--- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs
+++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EcosystemWallet/EcosystemWallet.cs
@@ -25,6 +25,7 @@ public partial class EcosystemWallet : IThirdwebWallet
internal readonly string PhoneNumber;
internal readonly string AuthProvider;
internal readonly string LegacyEncryptionKey;
+ internal readonly string WalletSecret;
internal string Address;
@@ -46,7 +47,8 @@ internal EcosystemWallet(
string phoneNumber,
string authProvider,
IThirdwebWallet siweSigner,
- string legacyEncryptionKey
+ string legacyEncryptionKey,
+ string walletSecret
)
{
this.Client = client;
@@ -59,6 +61,7 @@ string legacyEncryptionKey
this.PhoneNumber = phoneNumber;
this.AuthProvider = authProvider;
this.SiweSigner = siweSigner;
+ this.WalletSecret = walletSecret;
}
#region Creation
@@ -75,6 +78,7 @@ string legacyEncryptionKey
/// The path to the storage directory.
/// The SIWE signer wallet for SIWE authentication.
/// The encryption key that is no longer required but was used in the past. Only pass this if you had used custom auth before this was deprecated.
+ /// The wallet secret for Backend authentication.
/// A task that represents the asynchronous operation. The task result contains the created in-app wallet.
/// Thrown when required parameters are not provided.
public static async Task Create(
@@ -86,7 +90,8 @@ public static async Task Create(
AuthProvider authProvider = Thirdweb.AuthProvider.Default,
string storageDirectoryPath = null,
IThirdwebWallet siweSigner = null,
- string legacyEncryptionKey = null
+ string legacyEncryptionKey = null,
+ string walletSecret = null
)
{
if (client == null)
@@ -117,6 +122,7 @@ public static async Task Create(
Thirdweb.AuthProvider.Github => "Github",
Thirdweb.AuthProvider.Twitch => "Twitch",
Thirdweb.AuthProvider.Steam => "Steam",
+ Thirdweb.AuthProvider.Backend => "Backend",
Thirdweb.AuthProvider.Default => string.IsNullOrEmpty(email) ? "Phone" : "Email",
_ => throw new ArgumentException("Invalid AuthProvider"),
};
@@ -150,7 +156,7 @@ public static async Task Create(
try
{
var userAddress = await ResumeEnclaveSession(enclaveHttpClient, embeddedWallet, email, phoneNumber, authproviderStr).ConfigureAwait(false);
- return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner, legacyEncryptionKey)
+ return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner, legacyEncryptionKey, walletSecret)
{
Address = userAddress
};
@@ -158,7 +164,7 @@ public static async Task Create(
catch
{
enclaveHttpClient.RemoveHeader("Authorization");
- return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner, legacyEncryptionKey)
+ return new EcosystemWallet(ecosystemId, ecosystemPartnerId, client, embeddedWallet, enclaveHttpClient, email, phoneNumber, authproviderStr, siweSigner, legacyEncryptionKey, walletSecret)
{
Address = null
};
@@ -468,6 +474,13 @@ public async Task> LinkAccount(
}
serverRes = await ecosystemWallet.PreAuth_Siwe(ecosystemWallet.SiweSigner, chainId.Value).ConfigureAwait(false);
break;
+ case "Backend":
+ if (string.IsNullOrEmpty(ecosystemWallet.WalletSecret))
+ {
+ throw new ArgumentException("Cannot link account with a Backend wallet without a wallet secret.");
+ }
+ serverRes = await ecosystemWallet.PreAuth_Backend(ecosystemWallet.WalletSecret).ConfigureAwait(false);
+ break;
case "JWT":
if (string.IsNullOrEmpty(jwt))
{
@@ -692,12 +705,12 @@ public async Task LoginWithOauth(
private async Task PreAuth_Siwe(IThirdwebWallet siweSigner, BigInteger chainId)
{
- if (this.SiweSigner == null)
+ if (siweSigner == null)
{
throw new ArgumentNullException(nameof(siweSigner), "SIWE Signer wallet cannot be null.");
}
- if (!await this.SiweSigner.IsConnected().ConfigureAwait(false))
+ if (!await siweSigner.IsConnected().ConfigureAwait(false))
{
throw new InvalidOperationException("SIWE Signer wallet must be connected as this operation requires it to sign a message.");
}
@@ -716,6 +729,23 @@ public async Task LoginWithSiwe(BigInteger chainId)
#endregion
+ #region Backend
+
+ private async Task PreAuth_Backend(string walletSecret)
+ {
+ return string.IsNullOrEmpty(walletSecret)
+ ? throw new ArgumentException("Wallet secret cannot be null or empty.", nameof(walletSecret))
+ : await this.EmbeddedWallet.SignInWithBackendAsync(walletSecret).ConfigureAwait(false);
+ }
+
+ public async Task LoginWithBackend()
+ {
+ var serverRes = await this.PreAuth_Backend(this.WalletSecret).ConfigureAwait(false);
+ return await this.PostAuth(serverRes).ConfigureAwait(false);
+ }
+
+ #endregion
+
#region Guest
private async Task PreAuth_Guest()
@@ -746,13 +776,12 @@ public async Task LoginWithGuest()
private async Task PreAuth_JWT(string jwt)
{
- return string.IsNullOrEmpty(jwt) ? throw new ArgumentException(nameof(jwt), "JWT cannot be null or empty.") : await this.EmbeddedWallet.SignInWithJwtAsync(jwt).ConfigureAwait(false);
+ return string.IsNullOrEmpty(jwt) ? throw new ArgumentException("JWT cannot be null or empty.", nameof(jwt)) : await this.EmbeddedWallet.SignInWithJwtAsync(jwt).ConfigureAwait(false);
}
public async Task LoginWithJWT(string jwt)
{
- var serverRes = string.IsNullOrEmpty(jwt) ? throw new ArgumentException("JWT cannot be null or empty.", nameof(jwt)) : await this.EmbeddedWallet.SignInWithJwtAsync(jwt).ConfigureAwait(false);
-
+ var serverRes = await this.PreAuth_JWT(jwt).ConfigureAwait(false);
return await this.PostAuth(serverRes).ConfigureAwait(false);
}
diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs
index a396ff1..f4743fe 100644
--- a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs
+++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet.Authentication/Server.cs
@@ -16,6 +16,8 @@ internal abstract class ServerBase
internal abstract Task FetchSiwePayloadAsync(string address, string chainId);
internal abstract Task VerifySiweAsync(LoginPayloadData payload, string signature);
+ internal abstract Task VerifyBackendAsync(string walletSecret);
+
internal abstract Task VerifyGuestAsync(string sessionId);
internal abstract Task SendEmailOtpAsync(string emailAddress);
@@ -155,8 +157,19 @@ internal override async Task VerifySiweAsync(LoginPayloadData payl
return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false);
}
- // login/guest
+ // login/backend
+ internal override async Task VerifyBackendAsync(string walletSecret)
+ {
+ var uri = MakeUri2024("/login/backend");
+ var content = MakeHttpContent(new { walletSecret });
+ var response = await this._httpClient.PostAsync(uri.ToString(), content).ConfigureAwait(false);
+ await CheckStatusCodeAsync(response).ConfigureAwait(false);
+ var authResult = await DeserializeAsync(response).ConfigureAwait(false);
+ return await this.InvokeAuthResultLambdaAsync(authResult).ConfigureAwait(false);
+ }
+
+ // login/guest
internal override async Task VerifyGuestAsync(string sessionId)
{
var uri = MakeUri2024("/login/guest/callback");
diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Backend.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Backend.cs
new file mode 100644
index 0000000..d31e1cd
--- /dev/null
+++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/EmbeddedWallet/EmbeddedWallet.Backend.cs
@@ -0,0 +1,9 @@
+namespace Thirdweb.EWS;
+
+internal partial class EmbeddedWallet
+{
+ public async Task SignInWithBackendAsync(string walletSecret)
+ {
+ return await this._server.VerifyBackendAsync(walletSecret).ConfigureAwait(false);
+ }
+}
diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs
index 061e788..76d45d9 100644
--- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs
+++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.Types.cs
@@ -23,7 +23,8 @@ public enum AuthProvider
Coinbase,
Github,
Twitch,
- Steam
+ Steam,
+ Backend
}
///
diff --git a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs
index 8a7f8b8..168db0f 100644
--- a/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs
+++ b/Thirdweb/Thirdweb.Wallets/InAppWallet/InAppWallet.cs
@@ -16,9 +16,10 @@ internal InAppWallet(
string authProvider,
IThirdwebWallet siweSigner,
string address,
- string legacyEncryptionKey
+ string legacyEncryptionKey,
+ string walletSecret
)
- : base(null, null, client, embeddedWallet, httpClient, email, phoneNumber, authProvider, siweSigner, legacyEncryptionKey)
+ : base(null, null, client, embeddedWallet, httpClient, email, phoneNumber, authProvider, siweSigner, legacyEncryptionKey, walletSecret)
{
this.Address = address;
}
@@ -33,6 +34,7 @@ string legacyEncryptionKey
/// The path to the storage directory.
/// The SIWE signer wallet for SIWE authentication.
/// The encryption key that is no longer required but was used in the past. Only pass this if you had used custom auth before this was deprecated.
+ /// The wallet secret for backend authentication.
/// A task that represents the asynchronous operation. The task result contains the created in-app wallet.
/// Thrown when required parameters are not provided.
public static async Task Create(
@@ -42,11 +44,12 @@ public static async Task Create(
AuthProvider authProvider = Thirdweb.AuthProvider.Default,
string storageDirectoryPath = null,
IThirdwebWallet siweSigner = null,
- string legacyEncryptionKey = null
+ string legacyEncryptionKey = null,
+ string walletSecret = null
)
{
storageDirectoryPath ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Thirdweb", "InAppWallet");
- var ecoWallet = await Create(client, null, null, email, phoneNumber, authProvider, storageDirectoryPath, siweSigner, legacyEncryptionKey);
+ var ecoWallet = await Create(client, null, null, email, phoneNumber, authProvider, storageDirectoryPath, siweSigner, legacyEncryptionKey, walletSecret);
return new InAppWallet(
ecoWallet.Client,
ecoWallet.EmbeddedWallet,
@@ -56,7 +59,8 @@ public static async Task Create(
ecoWallet.AuthProvider,
ecoWallet.SiweSigner,
ecoWallet.Address,
- ecoWallet.LegacyEncryptionKey
+ ecoWallet.LegacyEncryptionKey,
+ ecoWallet.WalletSecret
);
}
}