AppKit provides a simple solution for integrating with “Sign-In With Ethereum” (SIWE), a new form of authentication that enables users to control their digital identity with their Ethereum account. SIWE is a standard also known as EIP-4361.

One-Click Auth

One-Click Auth represents a key advancement within WalletConnect v2, streamlining the user authentication process in AppKit by enabling them to seamlessly connect with a wallet and sign a SIWE message with just one click.

Connecting a wallet, proving control of an address with an off-chain signature, authorizing specific actions. These are the kinds of authorizations that can be encoded as “ReCaps”. ReCaps are permissions for a specific website or dapp that can be compactly encoded as a long string in the message you sign and translated by any wallet into a straight-forward one-sentence summary. WalletConnect uses permissions expressed as ReCaps to enable a One-Click Authentication.

One-Click Auth and Sign-In With Ethereum are currently not supported on WebGL.

Local Address Verification

When connecting wallets to applications using the WalletConnect protocol, the wallet supplies a list of accounts. However, there is a potential risk that the wallet could provide an address the user does not control. To mitigate this account spoofing risk, the standard practice is to require the user to sign a message with the provided address and then verify the signature.

The Sign-In With Ethereum (SIWE) feature in AppKit can facilitate this verification process, enabling the application to confirm the user’s Ethereum address even the app doesn’t have a backend.

0. Create basic SIWE configuration

// Create SIWE configuration
var siweConfig = new SiweConfig
{
    // The properties from `SiweMessageParams` be used to generate SIWE message.
    // There're no strict rules on what Domain and Uri parameters have to be on native platforms.
    // In this example we use website domain and app URL scheme.
    GetMessageParams = () => new SiweMessageParams
    {
        Domain = "mywebsite.com",
        Uri = "my-app://"
    },
    // By setting this to false, we disable a requirement to sign a new SIWE message
    // every time the active chain changes in AppKit or wallet.
    SignOutOnChainChange = false
};

// Subscribe to SIWE events
siweConfig.SignInSuccess += _ => Debug.Log("Address verified successfully!");
siweConfig.SignOutSuccess += () => Debug.Log("Address verification canceled or wallet disconnected.");

1. Initialize AppKit with your SiweConfig

Add the SIWE configuration to AppKitConfig

var appKitConfig = new AppKitConfig
{
    // Project ID from https://cloud.reown.com/
    projectId = "MY_PROJECT_ID",
    metadata = new Metadata(
        "App Name",
        "App Description",
        "https://reown.com",
        "https://raw.githubusercontent.com/reown-com/reown-dotnet/main/media/appkit-icon.png",
        new RedirectData
        {
            // Used by native wallets to redirect back to the app after approving requests
            Native = "my-app://"
        }
    ),
    // Assign the SIWE configuration created above. Can be null if SIWE is not used.
    siweConfig = siweConfig
};

With this configuration, AppKit will enforce address verification and invoke the SignInSuccess delegate when the user successfully verifies the address.

Sign-In With Ethereum with Backend

To use 1-CA + SIWE at full extend, a backend for communication is required. This backend will be used to generate a nonce, verify messages and handle sessions. You can read more about SIWE backend implementation at here.

0. Create SIWE configuration

var siweConfig = new SiweConfig
{
    GetNonce = async () =>
    {
        // The getNonce method functions as a safeguard against spoofing,
        // akin to a CSRF token.
        return await yourApi.getNonce();
    },
    // The properties from `SiweMessageParams` be used to generate SIWE message.
    // There's no strict rules on what Domain and Uri parameters have to be
    // on native platforms.
    // In this example we use website domain and app URL scheme.
    GetMessageParams = () =>
    {
        // Returns parameters that are used to create the SIWE message internally.
        return new SiweMessageParams
        {
            Domain = "mywebsite.com",
            Uri = "my-app://",
            // The custom statement that will be prepended to the SIWE message.
            // Optional.
            Statement = "My custom statement."
        };
    },
    CreateMessage = (createMessageArgs) =>
    {
        // Generates an EIP-4361-compatible message.
        // You can use our provided SiweUtils.FormatMessage
        // method (default behaviour if delegate is null) or implement your own.
        return SiweUtils.FormatMessage(createMessageArgs);
    },
    VerifyMessage = async (verifyMessageArgs) =>
    {
        // Ensures the message is valid, has not been tampered with,
        // and has been appropriately signed by the wallet address.
        try {
            var json = JsonConvert.SerializeObject(verifyMessageArgs);
            var isValidMessage = await yourApi.verifyMessage(json);
            return isValidMessage;
        } catch (Exception) {
            return false;
        }
    },
    GetSession = async (getSessionArgs) =>
    {
        // Called after VerifyMessage() succeeds
        // The backend session should store the associated address and chainId
        // and return it via the `getSession` method.
        var session = await yourApi.getSession();
        return new SiweSession
        {
            EthAddress = session.address,
            EthChainIds = session.ChainIdArray,
        };
    },
    SignOut = async () =>
    {
        // Called when the wallet disconnects if SignOutOnWalletDisconnect is true,
        // and/or when the account changes if SignOutOnAccountChange is true,
        // and/or when the network changes if SignOutOnChainChange is true.
        await yourApi.signOut();
    },
    SignOutOnAccountChange = true,
    SignOutOnChainChange = true,
    SignOutOnWalletDisconnect = true,
};

// Called after SiweConfig.GetSession() succeeds
siweConfig.SignInSuccess += _ => Debug.Log("[Dapp] SIWE Sign In Success!");

// Called after SiweConfig.SignOut() succeeds
siweConfig.SignOutSuccess += () => Debug.Log("[Dapp] SIWE Sign Out Success!");

1. Initialize AppKit with your SiweConfig

Add the SIWE configuration to AppKitConfig

var appKitConfig = new AppKitConfig
{
    // Project ID from https://cloud.reown.com/
    projectId = "MY_PROJECT_ID",
    metadata = new Metadata(
        "App Name",
        "App Description",
        "https://reown.com",
        "https://raw.githubusercontent.com/reown-com/reown-dotnet/main/media/appkit-icon.png",
        new RedirectData
        {
            // Used by native wallets to redirect back to the app after approving requests
            Native = "my-app://"
        }
    ),
    // Assign the SIWE configuration created above. Can be null if SIWE is not used.
    siweConfig = siweConfig
};