📢 Exclusive on Gate Square — #PROVE Creative Contest# is Now Live!
CandyDrop × Succinct (PROVE) — Trade to share 200,000 PROVE 👉 https://www.gate.com/announcements/article/46469
Futures Lucky Draw Challenge: Guaranteed 1 PROVE Airdrop per User 👉 https://www.gate.com/announcements/article/46491
🎁 Endless creativity · Rewards keep coming — Post to share 300 PROVE!
📅 Event PeriodAugust 12, 2025, 04:00 – August 17, 2025, 16:00 UTC
📌 How to Participate
1.Publish original content on Gate Square related to PROVE or the above activities (minimum 100 words; any format: analysis, tutorial, creativ
SIWE Technical Guide: Building an Ethereum Authentication System for Dapp
SIWE Technical Implementation Guide: Building a Robust Dapp Identification System
SIWE(Sign-In with Ethereum) is a way to verify user identification on Ethereum, similar to initiating a transaction, proving the user's control over the wallet. Currently, mainstream wallet plugins support this simple identification method, requiring only a signature in the plugin.
This article mainly discusses the signature scenarios on Ethereum and does not involve other public chains.
When to Use SIWE
If your Dapp has the following requirements, you may consider using SIWE:
For query-based applications, such as blockchain explorers similar to etherscan, SIWE may not be necessary.
Although it seems that the identification has been proven after connecting the wallet on the Dapp front end, it is not enough to only pass the address for API calls that require back-end support, because the address is public information and can be easily impersonated.
The Principle and Process of SIWE
The SIWE process can be summarized in three steps: connect the wallet, sign, and obtain identification.
Connect Wallet
This is a common Web3 operation, connecting a wallet in a Dapp through a wallet plugin.
signature
This includes three steps: obtaining the Nonce value, wallet signature, and backend signature verification.
Retrieve the randomly generated Nonce value from the backend, associated with the current address.
Construct the signature content on the front end, including Nonce value, domain name, chain ID, and other information, and sign it using the methods provided by the wallet.
Send the signature to the backend for verification.
obtain identification
After the backend verification of the signature is successful, return the user identification ( like JWT ). The frontend subsequent requests should include the address and identification to prove wallet ownership.
Practical Guide
The following will introduce how to implement SIWE functionality in a Nextjs project, returning a JWT for identification verification.
Environment Preparation
npx create-next-app@14
npm install antd @ant-design/web3 @ant-design/web3-wagmi wagmi viem @tanstack/react-query --save
Introduce Wagmi
Import WagmiProvider in layout.tsx:
javascript "use client"; import { getNonce, verifyMessage } from "@/app/api"; import { Mainnet, MetaMask, OkxWallet, TokenPocket, WagmiWeb3ConfigProvider, WalletConnect, ] from "@ant-design/web3-wagmi"; import { QueryClient } from "@tanstack/react-query"; import React from "react"; import { createSiweMessage } from "viem/siwe"; import { http } from "wagmi"; import { JwtProvider } from "./JwtProvider";
const YOUR_WALLET_CONNECT_PROJECT_ID = "c07c0051c2055890eade3556618e38a6"; const queryClient = new QueryClient();
const WagmiProvider: React.FC = ({ children }) => { const [jwt, setJwt] = React.useState((,null);
return ) <wagmiweb3configprovider siwe="{{" getnonce:="" async="" (address(=""> )await getNonce(address().data, createMessage: )props( => { return createSiweMessage){ ...props, statement: "Ant Design Web3" }(; }, verifyMessage: async )message, signature( => { const jwt = )await verifyMessage(message, signature().data; setJwt)jwt(; return !!jwt; }, }} chains={)} transports={{ [Mainnet.id]: http[Mainnet](, }} walletConnect={{ projectId: YOUR_WALLET_CONNECT_PROJECT_ID, }} wallets={[} MetaMask)(, WalletConnect)(, TokenPocket){ group: "Popular", }(, OkxWallet)(, ]} queryClient={queryClient} > {children} ); };
export default WagmiProvider;
![SIWE User Manual: How to Make Your Dapp More Powerful?])https://img-cdn.gateio.im/webp-social/moments-53c03d1cb26f29a9d739e3d1aa0816df.webp(
) Add connection button
Add connect wallet and sign buttons in the component:
javascript "use client"; import type { Account } from "@ant-design/web3"; import { ConnectButton, Connector } from "@ant-design/web3"; import { Flex, Space } from "antd"; import React from "react"; import { JwtProvider } from "./JwtProvider";
export default function App###( { const jwt = React.useContext)JwtProvider(;
const renderSignBtnText = ) defaultDom: React.ReactNode, account?: Account ( => { const { address } = account ?? {}; const ellipsisAddress = address ? ${address.slice)0, 6(}...${address.slice)-6(} : ""; return Sign in as ${ellipsisAddress}; };
return ) <>
![SIWE User Manual: How to Make Your Dapp More Powerful?])https://img-cdn.gateio.im/webp-social/moments-18a98c883797c414a689c54ae0d65302.webp(
) interface implementation
Nonce interface
javascript import { randomBytes } from "crypto"; import { addressMap } from "../cache";
export async function GET###request: Request( { const { searchParams } = new URL)request.url(; const address = searchParams.get)"address"(;
if )!address( { throw new Error)"Invalid address"(; } const nonce = randomBytes)16(.toString)("hex")(; addressMap.set)address, nonce(; return Response.json){ data: nonce, }(; }
)# Verification Signature Interface
javascript import { createPublicClient, http } from "viem"; import { mainnet } from "viem/chains"; import jwt from "jsonwebtoken"; import { parseSiweMessage } from "viem/siwe"; import { addressMap } from "../cache";
const JWT_SECRET = "your-secret-key";
const publicClient = createPublicClient###{ chain: mainnet, transport: http((, });
export async function POST)request: Request( { const { signature, message } = await request.json)(;
const { nonce, address = "0x" } = parseSiweMessage)message(;
if )!nonce || nonce !== addressMap.get(address() { throw new Error)"Invalid nonce"(; }
const valid = await publicClient.verifySiweMessage){ message, address, signature, }(;
if )!valid( { throw new Error)"Invalid signature"(; }
const token = jwt.sign){ address }, JWT_SECRET, { expiresIn: "1h" }(; return Response.json){ data: token, }(; }
![SIWE User Manual: How to Make Your Dapp Stronger?])https://img-cdn.gateio.im/webp-social/moments-9351d7f08e48962120d591c3a0c7d245.webp(
Optimization Suggestions
To improve the SIWE login speed, it is recommended to use dedicated node services. Taking the ZAN node service as an example, after obtaining the Ethereum mainnet HTTPS RPC connection, replace the default RPC of publicClient:
javascript const publicClient = createPublicClient){ chain: mainnet, transport: http('(, //ZAN node service RPC });
This can significantly reduce verification time and improve interface response speed.
![SIWE User Manual: How to Make Your Dapp More Powerful?])https://img-cdn.gateio.im/webp-social/moments-0ce46cff7473e96e768adfb5fc6dafb8.webp(