Skip to content

Create and recover wallets in Unity

Understanding embedded wallets

To create wallets for your users during the login flow, you need to configure the private key generation. The configuration depends on your chosen recovery method, so it's important to decide on your recovery strategy first.

Make sure to wait for the embedded state ready before using the embedded wallet. Learn more about how to check the embedded state.

Decide a recovery method

Recovering the embedded wallet is needed when a user logs into a new device or when the private key is lost.

Openfort embedded wallets have two core recovery modes: automatic recovery and user-based recovery. At a high-level, this setting modulates how the embedded wallet's recovery share is encrypted and stored.

  • Automatic recovery: The recovery share is encrypted with a combination of project entropy and Openfort's entropy. When logging into a new device, users can immediately access their embedded wallet.

    Shield configuration: Before configuring the automatic recovery, generate your project's publishable and secret shield keys and store the encryption share. Learn about the differrent API keys here.

  • User-based recovery: The recovery share is encrypted by user-provided entropy. When logging into a new device, users must enter in their password to recover the embedded wallet on the new device. Once the private key has been recovered on a device, users will not need to enter their password on that devices again.

Automatic recovery

It is worth noting that while automatic recovery makes for smooth user UX (without needing to set up a recovery system upfront when logging in), it comes with tradeoffs. Notably, the root of trust with is in the user’s authentication token. This means access to the auth token grants access to the wallet. Accordingly, this token must be properly secured at all times.

When using automatic recovery, Shield generates a password that is used for the encryption of the recovery share. The full encryption key can only be accessed if the decryption request includes the user's auth token.

⚠️ Encryption share: When using automatic recovery, its very important to ensure that the encryption share should not be available from the client side of the application.

From your backend, you should have an endpoint that generates an encryption session for the user. This endpoint should be protected and only accessible by the user who is requesting the encryption session (i.e. the user who is logging in).

Note: An encryption session is requested every time configureEmbeddedSigner is called. The encryption session is only valid for a single use.

For example, in a Next.js API route, you can create an endpoint like this:

import openfort from "./openfortAdminConfig";
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const session = await openfort.registerRecoverySession(
    "YOUR_SHIELD_PUBLISHABLE_KEY",
    "YOUR_SHIELD_SECRET_KEY",
    "YOUR_SHIELD_ENCRYPTION_SHARE"
  );
  res.status(200).send({
    session: session,
  });
}
import Openfort from "@openfort/openfort-node";
 
const openfort = new Openfort("YOUR_OPENFORT_SECRET_KEY");
 
export default openfort;

Once we've secured the backend we setup the client side:

Openfort Auth

using System;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using Openfort.OpenfortSDK;
using Openfort.OpenfortSDK.Model;
using static Clients.Shield;
 
public class EmbeddedSignerManager : MonoBehaviour
{
    private OpenfortSDK openfort;
 
    // Setup with Openfort authentication
    public async Task SetupAutomaticRecoveryWithOpenfort(string email, string password)
    {
        try
        {
            // Sign up the user
            AuthResponse response = await openfort.auth.signUpWithEmailPassword(email, password);
            string token = response.Token;
 
            // Get encryption session from your backend
            string encryptionSession = await GetEncryptionSession();
 
            // Configure the signer
            int chainId = 80002; // Polygon Amoy testnet
            ShieldAuthentication shieldAuthentication = new ShieldAuthentication(
                ShieldAuthType.Openfort,
                token
            )
            {
                EncryptionSession = encryptionSession
            };
 
            EmbeddedSignerRequest request = new EmbeddedSignerRequest({chainId, shieldAuthentication});
            await openfort.embeddedWallet.configure(request);
 
            Debug.Log("Automatic recovery setup complete");
        }
        catch (Exception e)
        {
            Debug.LogError(quot;Error setting up automatic recovery: {e.Message}");
        }
    }
}
using System;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
 
public class EncryptionSessionManager
{
    public static async Task<string> GetEncryptionSession()
    {
        string url = "https://your-api-endpoint.com/api/protected-create-encryption-session";
 
        using (UnityWebRequest webRequest = UnityWebRequest.Post(url, "{}"))
        {
            webRequest.SetRequestHeader("Content-Type", "application/json");
 
            var operation = webRequest.SendWebRequest();
 
            while (!operation.isDone)
                await Task.Yield();
 
            if (webRequest.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError(quot;Failed to create encryption session: {webRequest.error}");
                throw new Exception("Failed to create encryption session");
            }
 
            string jsonResponse = webRequest.downloadHandler.text;
            SessionResponse response = JsonUtility.FromJson<SessionResponse>(jsonResponse);
            return response.session;
        }
    }
}
 
[Serializable]
public class SessionResponse
{
    public string session;
}

Third-party Auth

This example will showcase Firebase as the third-party auth provider. You can replace it with any other third-party auth provider.

using System;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using Openfort.OpenfortSDK;
using Openfort.OpenfortSDK.Model;
using static Clients.Shield;
 
public async Task SetupAutomaticRecoveryWithThirdParty(string idToken)
    {
        try
        {
            // Authenticate with third-party provider
            await openfort.auth.authenticateWithThirdPartyProvider(
                new ThirdPartyProviderRequest(
                    ThirdPartyOAuthProvider.Firebase,
                    idToken,
                    TokenType.IdToken
                )
            );
 
            // Get encryption session from your backend
            string encryptionSession = await GetEncryptionSession();
 
            // Configure the signer
            int chainId = 80002;
            ShieldAuthentication shieldAuthentication = new ShieldAuthentication(
                ShieldAuthType.Openfort,
                idToken,
                "firebase",
                "idToken"
            )
            {
                EncryptionSession = encryptionSession
            };
 
            EmbeddedSignerRequest request = new EmbeddedSignerRequest({chainId, shieldAuthentication});
            await openfort.embeddedWallet.configure(request);
 
            Debug.Log("Third-party automatic recovery setup complete");
        }
        catch (Exception e)
        {
            Debug.LogError(quot;Error setting up third-party automatic recovery: {e.Message}");
        }
    }
using System;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
 
public class EncryptionSessionManager
{
    public static async Task<string> GetEncryptionSession()
    {
        string url = "https://your-api-endpoint.com/api/protected-create-encryption-session";
 
        using (UnityWebRequest webRequest = UnityWebRequest.Post(url, "{}"))
        {
            webRequest.SetRequestHeader("Content-Type", "application/json");
 
            var operation = webRequest.SendWebRequest();
 
            while (!operation.isDone)
                await Task.Yield();
 
            if (webRequest.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError(quot;Failed to create encryption session: {webRequest.error}");
                throw new Exception("Failed to create encryption session");
            }
 
            string jsonResponse = webRequest.downloadHandler.text;
            SessionResponse response = JsonUtility.FromJson<SessionResponse>(jsonResponse);
            return response.session;
        }
    }
}
 
[Serializable]
public class SessionResponse
{
    public string session;
}

💡 Tip: We recommend enabling user-based recovery for users. This is especially important to enforce as the value of assets in a user's wallet grows.


User-based recovery

Password recovery

Require that users set a password when the wallet is created, enforcing password-based recovery from the start.

If encrypted by user-provided entropy, only the user can decrypt the recovery share. Openfort never sees the user's password. Therefore, if you're not planning to ever user the automatic recovery mode, you can use the encryption share in the client side of the application.

Openfort Auth

using Openfort.OpenfortSDK;
using Openfort.OpenfortSDK.Model;
public class openfortManager: MonoBehaviour
{
    private OpenfortSDK Openfort;
    private async void AuthAndSetPassordRecoveryMethod(string email, string password, string recoveryPassword)
    {
        AuthResponse response = await openfort.auth.signUpWithEmailPassword(email, password);
        string token = response.Token;
        int chainId = 80002;
        ShieldAuthentication shieldAuthentication = new ShieldAuthentication(ShieldAuthType.Openfort, token);
        RecoveryParams recoveryParams = new RecoveryParams
        {
            password = recoveryPassword,
            recoveryMethod = RecoveryMethod.PASSWORD
        };
        EmbeddedSignerRequest request = new EmbeddedSignerRequest({chainId, shieldAuthentication, recoveryParams});
        await openfort.embeddedWallet.configure(request);
    }
}

Third-party Auth

This example will showcase Firebase as the third-party auth provider. You can replace it with any other third-party auth provider supported by Openfort.

using Openfort.OpenfortSDK;
using Openfort.OpenfortSDK.Model;
public class openfortManager: MonoBehaviour
{
    private OpenfortSDK Openfort;
    private async void AuthAndSetPassordRecoveryMethod(string token, string recoveryPassword)
    {
        await openfort.auth.authenticateWithThirdPartyProvider(new ThirdPartyProviderRequest(ThirdPartyOAuthProvider.Firebase, token, TokenType.IdToken));
        int chainId = 80002;
        ShieldAuthentication shieldAuthentication = new ShieldAuthentication(ShieldAuthType.Openfort, token, "firebase", "idToken");
        RecoveryParams recoveryParams = new RecoveryParams
        {
            password = recoveryPassword,
            recoveryMethod = RecoveryMethod.PASSWORD
        };
        EmbeddedSignerRequest request = new EmbeddedSignerRequest({chainId, shieldAuthentication, recoveryParams});
        await openfort.embeddedWallet.configure(request);
    }
}

Pregeneration

Openfort also allows you to pregenerate embedded wallets for your users, even before they first login to your game. Please see our pregeneration guide for more.