Skip to main content

Nethereum.Siwe

NuGet: Nethereum.Siwe | Source: src/Nethereum.Siwe/

Nethereum.Siwe

Full Sign-In with Ethereum (EIP-4361) implementation with session management, signature verification, and pluggable user validation. Built on top of Nethereum.Siwe.Core.

Key Components

ClassPurpose
SiweMessageServiceOrchestrates the full SIWE flow: message building with nonce, signature verification, session matching, expiry checks
ISessionStorageInterface for storing SIWE sessions keyed by nonce
InMemorySessionNonceStorageDefault in-memory session store (uses ConcurrentDictionary)
IEthereumUserServicePluggable user validation (e.g. check NFT balance, database lookup)
ERC721BalanceEthereumUserServiceValidates users hold an ERC-721 token
RandomNonceBuilderGenerates cryptographically random nonces for SIWE messages

Quick Start

Server-side SIWE authentication

// 1. Create the service (in-memory sessions, no user validation)
var siweService = new SiweMessageService();

// 2. Build a message for the user to sign
var message = new SiweMessage
{
Domain = "example.com",
Address = userAddress.ConvertToEthereumChecksumAddress(),
Statement = "Sign in to Example",
Uri = "https://example.com",
Version = "1",
ChainId = "1"
};
message.SetExpirationTime(DateTime.UtcNow.AddMinutes(10));
message.SetNotBefore(DateTime.UtcNow);
string messageToSign = siweService.BuildMessageToSign(message);
// Send messageToSign to the client for signing

// 3. Verify the signed message
var parsed = SiweMessageParser.Parse(messageToSign);
bool valid = await siweService.IsValidMessage(parsed, signature);

With NFT-gated access

var userService = new ERC721BalanceEthereumUserService(nftContractAddress, rpcUrl);
var siweService = new SiweMessageService(
new InMemorySessionNonceStorage(),
userService);

// IsUserAddressRegistered checks the user holds the NFT
bool registered = await siweService.IsUserAddressRegistered(parsed);

Smart contract wallet support (ERC-1271 / ERC-6492)

var siweService = new SiweMessageService(
new InMemorySessionNonceStorage(),
ethereumUserService: null,
web3ForERC1271Validation: web3);

// IsMessageSignatureValid automatically falls back to ERC-1271/ERC-6492
// for smart contract wallets
bool valid = await siweService.IsMessageSignatureValid(parsed, signature);

SiweMessageService API Reference

Constructor

// Default: in-memory sessions, no user validation, EOA signatures only
var service = new SiweMessageService();

// Full: custom session storage, user validation, smart contract wallet support
var service = new SiweMessageService(
sessionStorage: new InMemorySessionNonceStorage(),
ethereumUserService: myUserService, // optional
web3ForERC1271Validation: web3); // optional

Methods

MethodDescription
BuildMessageToSign(SiweMessage)Assigns a new nonce, stores the session, and returns the canonical string for signing
IsValidMessage(SiweMessage, string)Full validation: signature + dates + session match + user registration
IsMessageSignatureValid(SiweMessage, string)Validates signature only (EOA via EthereumMessageSigner, or ERC-1271/ERC-6492 for smart wallets)
HasMessageDateStartedAndNotExpired(SiweMessage)Checks NotBefore and ExpirationTime against current UTC time
IsMessageTheSameAsSessionStored(SiweMessage)Verifies the message matches the session stored under its nonce
IsUserAddressRegistered(SiweMessage)Delegates to the configured IEthereumUserService (returns true if none configured)
AssignNewNonce(SiweMessage)Generates a random nonce via RandomNonceBuilder and stores the session
InvalidateSession(SiweMessage)Removes the session entry for the given message's nonce

RandomNonceBuilder

Generates cryptographically secure nonces by signing a timestamped challenge with a random key and hashing the result:

string nonce = RandomNonceBuilder.GenerateNewNonce();

Session Storage

Implement ISessionStorage to customize session persistence (e.g. Redis, database):

public interface ISessionStorage
{
void AddOrUpdate(SiweMessage siweMessage);
SiweMessage GetSiweMessage(SiweMessage siweMessage);
void Remove(SiweMessage siweMessage);
void Remove(string nonce);
}

The default InMemorySessionNonceStorage uses a ConcurrentDictionary<string, SiweMessage> keyed by nonce.

User Validation

Implement IEthereumUserService to add custom user authorization checks:

public interface IEthereumUserService
{
Task<bool> IsUserAddressRegistered(string address);
}

The built-in ERC721BalanceEthereumUserService checks whether the user holds at least one token from an ERC-721 contract:

// Provide the NFT contract address and an RPC URL
var userService = new ERC721BalanceEthereumUserService(nftContractAddress, rpcUrl);

Authentication (REST API)

For .NET 5.0+ applications, SiweApiUserLoginService<TUser> provides a REST API client for SIWE-based authentication flows with JWT tokens:

var loginService = new SiweApiUserLoginService<User>(
new HttpClient { BaseAddress = new Uri("https://api.example.com") });

// 1. Request a fresh SIWE message from the server
string messageToSign = await loginService.GenerateNewSiweMessage(ethereumAddress);

// 2. User signs the message (client-side), then authenticate
var response = await loginService.Authenticate(parsedMessage, signature);
// response.Jwt — JWT token for subsequent API calls
// response.Address — authenticated Ethereum address

// 3. Get user details
var user = await loginService.GetUser(response.Jwt);

// 4. Logout
await loginService.Logout(response.Jwt);

User Model

public class User
{
public string EthereumAddress { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
}

Full Template

A complete Blazor + REST API SIWE authentication template is available at Nethereum.Templates.Siwe, providing:

  • REST API — Nonce generation, authentication endpoint, JWT creation and middleware validation
  • Blazor WebAssembly — MetaMask signing, JWT local storage, SiweAuthenticationWasmStateProvider
  • Blazor Server — Direct signing via NethereumSiweAuthenticatorService, protected session storage
  • Blazor <AuthorizeView> — Role-based access with EthereumConnected and SiweAuthenticated claims

Relationship to Other Packages

  • Nethereum.Siwe.Core — Message model, parser, string builder, and RECAP capabilities
  • Nethereum.UINethereumSiweAuthenticatorService for Blazor Server SIWE flows
  • Nethereum.SignerEthereumMessageSigner used for signature recovery
  • Nethereum.Contracts — ERC-1271 and ERC-6492 signature validation for smart contract wallets