Wallets, chains and endpoints

The two chain lists that must agree, which wallets can actually complete a sign-in, every endpoint the addon adds, and every variable it reads.

4 min readUpdated 6 August 2026reference, chains, endpoints, environment, eip155

Everything on this page is fixed in code. There is no admin screen and no environment variable that changes any of it.

Chains

There are two lists and they are maintained separately.

The frontend pickerfrontend/config/wallet.tsx — decides which networks the Reown modal offers and what Chain ID: ends up in the signed message.

The backend allow-listbackend/src/api/auth/utils.ts — decides which chain IDs are accepted at verification. A chain outside it is refused with 401 and an Unsupported SIWE chainId line in the backend log, before any network call is made.

Chain eip155 ID Offered by the picker Accepted by the backend
Ethereum Mainnet 1 Yes — the default network Yes
Optimism 10 Yes Yes
BNB Smart Chain 56 Yes Yes
Polygon 137 Yes Yes
Arbitrum One 42161 Yes Yes
Base 8453 Yes Yes
Avalanche C-Chain 43114 No Yes
Sepolia (testnet) 11155111 No Yes

Two behaviours follow.

Avalanche and Sepolia are unreachable in stock form. The backend would accept them; the picker never produces them. They only become usable if you add them to the frontend list.

A message with no Chain ID: line is treated as Ethereum mainnet. The parser defaults to 1 when the line is absent, so verification is routed to mainnet rather than refused.

The chain ID from the user-supplied message is interpolated into the RPC URL that verifies the signature. Widening the list to accept an arbitrary value would let a caller point verification at an endpoint of their choosing, which is the same as letting them decide whether their own signature is valid.

If you add a chain, add a specific eip155:<id> entry to the backend set. Never remove the check.

Adding a chain means editing both files and then rebuilding the frontend and restarting the backend. Adding it to only one produces a network users can pick and cannot sign in on.

Wallets

The Reown modal lists every wallet in the WalletConnect registry, and any of them can complete the connect step. Completing the sign step is narrower.

Both the login form and the profile Wallet tab build an ethers provider from window.ethereum to request the signature, rather than from the AppKit connector that the user just chose. If no injected provider exists, the flow stops with "Ethereum provider not found. Please install MetaMask."

In practice:

Situation Connect Sign
Desktop browser with MetaMask, Rabby, Coinbase Wallet extension or similar Works Works
Mobile wallet's in-app browser (MetaMask, Trust, Coinbase) Works Works — those browsers inject a provider
Desktop browser, no extension, WalletConnect QR to a phone Works Fails — no injected provider to sign with
Smart-contract wallet (Safe and similar) reached through an injected provider Works Works — verification falls through to EIP-1271 on the named chain

There is a second consequence of reading the injected provider directly: the address that signs is whichever account that provider currently has selected, which is not necessarily the address AppKit is displaying. A user with several accounts in one extension can connect as one and sign as another, and the sign-in then fails with "Wallet address not recognized" for an address they never intended to use.

The four names shown on the profile Wallet tab — MetaMask, WalletConnect, Coinbase, Trust Wallet — are static labels in that page, not a capability list.

Endpoints

All three are added by this addon. None of them carries a permission key; two are public and one requires a session.

Issues a single-use SIWE nonce. Public. Rate limited to 5 requests per 15 minutes per IP, shared.
Verifies a SIWE signature and issues session cookies. Public. Same shared rate limit.
Links a verified address to the signed-in account. Requires a session.
Removes a wallet link. Requires a session. Not gated on the extension.

Request and response shapes

POST /api/auth/login/wallet and POST /api/user/profile/wallet/connect take the same body:

{
  "message": "<the full SIWE message the user signed>",
  "signature": "0x…"
}

A successful sign-in returns a message plus the three cookies the framework converts into Set-Cookie headers — accessToken, sessionId and csrfToken. A sign-in that hits the 2FA gate returns 200 with twoFactor, twoFactorToken and no cookies at all; see The sign-in flow.

POST /api/user/profile/wallet/disconnect takes { "address": "0x…" }.

Where the linked address is readable

Returns the signed-in user, including a providers array of linked Google and WALLET identities

The providers array is the only place a linked wallet is exposed by the API. Each entry is { provider, providerUserId }. There is no admin endpoint that lists wallet links.

Licence and enable gating

Thing Value
Extension name (the extension table) wallet_connect
Envato item ID / product ID 37548018
Licence file the handlers check for lic/37548018.lic in the project root
Store slug wallet-connect
Admin permissions to enable it view.extension, edit.extension

Unlike every other addon, Wallet Connect has no route prefix registered for licence enforcement. Its endpoints sit under /api/auth and /api/user/profile, both of which are on the licence-exempt list so that login survives a core licence being re-activated. The check therefore runs inside the three gated handlers, and it tests two things: that wallet_connect is present in the enabled-extension cache, and that the .lic file exists on disk. Either one failing returns 403 "Wallet authentication is not enabled on this platform" or 403 "Wallet Connect extension license is not activated".

The enabled-extension cache only ever holds rows with status = true, and is invalidated when an admin toggles an extension, so the toggle takes effect without a restart.

Environment variables

The Reown project ID. Read by the frontend at BUILD time and by the backend at module load. Not in .env.example. Without it the backend returns 500 on sign-in while the frontend falls back to a hard-coded ID and appears to work.
Application name shown in the wallet's approval sheet.
Description shown beneath the name in the approval sheet.
Fallback origin for the approval sheet when it cannot be read from the browser.

The addon reads no others. It has no rows in the settings table, and the 2FA behaviour it inherits is governed by the core's own twoFactorStatus, twoFactorEmailStatus and twoFactorSmsStatus settings.

Outbound network requirements

From To Purpose If blocked
Browser Reown relay and registry Wallet discovery and the WalletConnect session The picker fails to load wallets
Backend rpc.walletconnect.org Signature verification Every sign-in returns 401

The backend leg is the one people miss. A server with locked-down egress will verify nothing, and the failure looks exactly like a bad signature: the wallet prompt succeeds, the user is refused, and there is a Signature verification error line in the backend log.

Data model

-- provider_user  (shared with Google sign-in)
id             CHAR(36)      PRIMARY KEY
userId         CHAR(36)      NOT NULL   -- FK user.id, ON DELETE CASCADE
providerUserId VARCHAR(255)  NOT NULL   -- UNIQUE across both provider types, LOWERCASED on write
provider       ENUM('GOOGLE','WALLET')  NOT NULL
isPrimary      TINYINT(1)               -- TRUE or NULL, never FALSE
chainId        INT                      -- EIP-155 chain the signature was proven on
verifiedAt     DATETIME                 -- when that signature was verified
createdAt / updatedAt / deletedAt       -- soft-delete columns
UNIQUE KEY (providerUserId)
UNIQUE KEY (userId, provider, isPrimary)

The user table also carries walletAddress and walletProvider. They are a denormalised copy of the primary WALLET link, written only by the afterSave and afterDestroy hooks on providerUser and defended by a guard on the user model that throws for every other writer. They are NULL for a user with no linked wallet, and they never hold a second linked address — read Linking a wallet before you rely on either.

Package versions

Declared across the root and frontend package manifests. These are the versions this addon's behaviour is described against.

Package Version
@reown/appkit 1.8.15
@reown/appkit-adapter-wagmi 1.8.15
wagmi ^2.19.5
viem ^2.55.10
ethers ^6.17.0
siwe ^3.0.0