Skip to main content

Overview

Sign In With Ethereum (SIWE, EIP-4361) lets users authenticate using an Ethereum wallet they already own. Instead of a password or OTP, the user signs a structured message with their private key, proving ownership of an address. This approach is ideal when:
  • Your users already have Ethereum wallets (Base App, Base Account, MetaMask, Phantom, hardware wallets, etc.)
  • You want a crypto-native sign-in experience without email or phone number requirements
  • You need to tie the user wallet identity to an on-chain address
On first sign-in, CDP can automatically create an embedded user wallet and associate it with the user’s Ethereum address. Control this with the ethereum.createOnLogin config option ("eoa" or "smart"). To disable automatic creation and provision wallets manually, omit createOnLogin from your config.

How it works

SIWE authentication is a two-step flow:
Your app calls signInWithSiwe with the user’s Ethereum address and context about your application. CDP returns a standards-compliant EIP-4361 message containing a cryptographic nonce, expiration time, and the parameters you provided. Present this message to the user’s wallet for signing.
After the user signs the message with their wallet, call verifySiweSignature with the flowId from step 1 and the resulting signature. CDP verifies the signature on-chain, and on success, returns an authenticated user with a user wallet.
  • Cryptographic proof: Authentication requires a valid signature from the private key controlling the address — no credential sharing
  • Replay protection: Each challenge contains a unique nonce and an expiration time
  • Domain binding: The domain field ties the signed message to your application, preventing cross-site replay attacks
  • Rate limiting: Protection against brute force attempts

Choosing an integration path

Try SIWE live at demo.cdp.coinbase.com. Enable Sign in with Base in the demo’s config panel to see siwe:base in action alongside email, SMS, and OAuth methods.

Sign in with Base

Sign in with Base is a first-party SIWE auth method for CDP React apps. Add "siwe:base" to your authMethods config and CDP renders a Continue with Base button that handles wallet connection, message signing, and verification automatically. Under the hood, CDP uses the Base Account SDK (@base-org/account) to connect the user’s Base Account, then runs the standard SIWE flow (signInWithSiwepersonal_signverifySiweSignature). The chainId is read from the connected wallet at sign-in time. Unlike OAuth providers, no CDP Portal configuration is required — enable the method in your app config and install the Base Account SDK.

Prerequisites

Install the CDP React packages and the Base Account SDK:
@base-org/account is an optional peer dependency of @coinbase/cdp-react. If it is not installed, clicking Continue with Base will fail with an error asking you to install the package.

Enable in your config

Add "siwe:base" to the authMethods array in your CDPReactProvider config. Set appName — it is passed to the Base Account SDK during wallet connection.
The authMethods value uses the siwe:<provider> format. Today the supported provider is "base" (i.e. "siwe:base"). See the AuthMethod and SIWE_METHODS type references for details.

Combining with other auth methods

siwe:base works alongside email, SMS, and OAuth methods in the same authMethods array. Users pick their preferred method from the sign-in UI:
When multiple methods are enabled, SignInAuthMethodButtons renders a button for each. Filter methods on individual components with the authMethods prop if needed.

SDK integration

React hooks (custom wallet)

Use useSignInWithSiwe and useVerifySiweSignature from @coinbase/cdp-hooks when you manage wallet connection yourself (for example, with wagmi or viem). You are responsible for obtaining the user’s address, connecting their wallet, and signing the challenge message.
The chainId must match the network the user’s wallet is on. Common values: 8453 (Base mainnet), 84532 (Base Sepolia), 1 (Ethereum mainnet). When using Sign in with Base, CDP reads the chain ID from the connected Base wallet automatically.

Non-React

For vanilla JavaScript/TypeScript or other frameworks, import directly from @coinbase/cdp-core:

Auth method linking

Users who are already signed in can link a SIWE address to their account so they can sign in with their external wallet later. Use useLinkSiwe from @coinbase/cdp-hooks — it follows the same two-step challenge-and-verify flow as useSignInWithSiwe, but associates the address with the current session instead of creating a new one. When a signed-in user clicks Continue with Base in CDP React, the SDK automatically calls linkSiwe instead of signInWithSiwe. See Auth Method Linking for the full linking guide and LinkAuth component examples.

Parameters

signInWithSiwe options

signInWithSiwe result

verifySiweSignature options

verifySiweSignature result

Optional message fields

You can include a statement to display a human-readable action the user is approving, and resources to enumerate URIs the user acknowledges:
The resulting EIP-4361 message will include these fields, making the user’s intent explicit in the signature payload.

Troubleshooting

Install the Base Account SDK in your project:
This package is an optional peer dependency of @coinbase/cdp-react — it is only required when "siwe:base" is in your authMethods.
The signed message must be submitted to verifySiweSignature before the expirationTime returned in step 1. If the user takes too long to sign, or the page is left open, request a new challenge by calling signInWithSiwe again.
If the user dismisses the wallet signing prompt, the flow fails gracefully. Prompt them to try again — each attempt creates a fresh challenge with a new nonce.
The chainId passed to signInWithSiwe must match the network the user’s wallet is connected to. For custom wallet integrations, read the chain ID from the connected provider. For Sign in with Base, CDP handles this automatically.
Challenge expiration: The signed message must be submitted to verifySiweSignature before the expirationTime returned in step 1. Expired challenges will be rejected.