Embedded Wallets SDK for Node.js
Overview
The MetaMask Embedded Wallets Node.js SDK (formerly Web3Auth Node SDK) is a backend solution designed for server-side authentication and key management. This SDK enables seamless integration of Web3 authentication into backend applications, AI agents, and programmatic use cases.
Unlike frontend SDKs, the Node.js SDK is stateless and sessionless, making it ideal for:
- Backend AI agents
- Server-side wallet operations
- Programmatic blockchain interactions
- Custodial wallet services
Key Features
- Stateless Architecture: No session management required
- Multi-Chain Support: EVM chains, Solana, and other blockchains
- Custom Authentication: Mandatory custom auth with single key share
- Private Key Access: Direct access to private keys for any blockchain
- Backend-Optimized: Designed specifically for server environments
Requirements
- Node.js 18+
- Custom authentication setup (mandatory)
- Web3Auth Dashboard project configuration
Installation
Install the Web3Auth Node SDK
- npm
- Yarn
- pnpm
- Bun
npm install --save @web3auth/node-sdk
yarn add @web3auth/node-sdk
pnpm add @web3auth/node-sdk
bun add @web3auth/node-sdk
Setup
Before you start, make sure you have:
- Registered on the Web3Auth Dashboard
- Set up a project with a custom Auth Connection (mandatory for Node.js SDK)
1. Custom Authentication Setup (Required)
The Node.js SDK only supports custom authentication. You must create a custom auth connection in the Web3Auth Dashboard:
- Go to Web3Auth Dashboard
- Select your project
- Navigate to Authentication → Custom Connections
- Click Create connections
- Configure your auth connection with your custom JWT details
You can refer to the Custom JWT Setup guide to learn more.
2. SDK Configuration
Create a Web3Auth instance with your client ID, web3auth network name, and chain information:
const web3auth = new Web3Auth({
clientId: 'YOUR_CLIENT_ID', // Get your Client ID from Web3Auth Dashboard
web3AuthNetwork: 'sapphire_mainnet', // or 'sapphire_devnet'
defaultChainId: '0x1', // or '0x89' for Polygon
})
The chain information is optional and will be used to setup the provider for connecting to the chain. If not provided, the first chain in the list will be used.
3. Initialize Web3Auth
Initialize the Web3Auth instance during your application startup:
await web3auth.init()
6. Authenticate Users
Use the connect method with your custom authentication parameters:
const provider = await web3auth.connect({
verifier: 'YOUR_VERIFIER_NAME', // Your custom verifier name
verifierId: 'USER_VERIFIER_ID', // User's unique identifier
idToken: 'USER_ID_TOKEN', // JWT token from your auth system
})
Configuration Options
- Basic Configuration
- Advanced Configuration
const { Web3Auth } = require('@web3auth/node-sdk')
const web3auth = new Web3Auth({
clientId: 'YOUR_CLIENT_ID',
web3AuthNetwork: 'sapphire_mainnet', // or 'sapphire_devnet'
})
await web3auth.init()
const web3auth = new Web3Auth({
clientId: 'YOUR_CLIENT_ID',
web3AuthNetwork: 'sapphire_mainnet', // or 'sapphire_devnet'
defaultChainId: '0x1', // or '0x89' for Polygon
enableLogging: true,
sessionTime: 3600,
})
await web3auth.init()
Configuration Parameters
- Table
- Interface
Web3Auth Configuration
Parameter | Type | Default | Description |
---|---|---|---|
clientId | string | Required | Your Web3Auth client ID |
web3AuthNetwork | string | Required | Network: 'sapphire_mainnet' or 'sapphire_devnet' |
defaultChainId | string | Optional | Chain ID to use for the default chain (e.g., '0x1' for Ethereum) |
Advanced Configuration Parameters
| Parameter | Type | Description |
| ----------------- | --------- | ----------- | ------------------------------------------------------------------- |
| chains
| object
| Optional | Chains to use for the authentication. It takes Chains
as a value. |
| enableLogging
| boolean
| Optional | Setting to true will enable logs. Default is false. |
| usePnPKey
| boolean
| Optional | Setting to true will use the PnP key. Default is false. |
| useDKG
| boolean
| Optional | Setting to true will use the DKG. Default is false. |
| checkCommitment
| boolean
| Optional | Setting to true will check the commitment. Default is true. |
export interface Web3AuthOptions {
/**
* Client id for web3auth.
* You can obtain your client id from the web3auth developer dashboard.
* You can set any random string for this on localhost.
*/
clientId: string;
/**
* Web3Auth Network to use for login
* @defaultValue mainnet
*/
web3AuthNetwork?: WEB3AUTH_NETWORK_TYPE;
/**
* multiple chain configurations,
* only provided chains will be used
*/
chains?: CustomChainConfig[];
/**
* default chain Id to use
*/
defaultChainId?: string;
/**
* setting to true will enable logs
*
* @defaultValue false
*/
enableLogging?: boolean;
/**
* setting this to true returns the same key as web sdk (i.e., plug n play key)
* By default, this sdk returns SFAKey
*/
usePnPKey?: boolean;
/**
* set this to true when you wants keys/shares to be generated by a dkg network
*
* Default:- false for sapphire network and always true for legacy networks.
* Legacy networks doesnt support non dkg flow. So this is always true for legacy networks.
*/
useDKG?: boolean;
/**
* setting this to true will check the commitment of the shares
*
* @defaultValue true
*/
checkCommitment?: boolean;
}
Best Practices
Environment Variables
Store sensitive configuration in environment variables:
# .env file
WEB3AUTH_CLIENT_ID=your_client_id_here
WEB3AUTH_NETWORK=sapphire_mainnet
SESSION_TIMEOUT=3600
ENABLE_LOGGING=false
Configuration Validation
function validateConfig(config) {
if (!config.clientId) {
throw new Error('Client ID is required')
}
if (!['sapphire_mainnet', 'sapphire_devnet'].includes(config.web3AuthNetwork)) {
throw new Error('Invalid Web3Auth network')
}
if (config.sessionTime < 300) {
throw new Error('Session time must be at least 5 minutes')
}
return config
}
const config = validateConfig({
clientId: process.env.WEB3AUTH_CLIENT_ID,
web3AuthNetwork: process.env.WEB3AUTH_NETWORK,
sessionTime: parseInt(process.env.SESSION_TIMEOUT),
})
Dynamic Configuration Manager
class Web3AuthConfigManager {
constructor() {
this.config = this.loadConfig()
}
loadConfig() {
const baseConfig = {
clientId: process.env.WEB3AUTH_CLIENT_ID,
web3AuthNetwork: process.env.WEB3AUTH_NETWORK || 'sapphire_devnet',
usePnPKey: false,
}
// Environment-specific overrides
switch (process.env.NODE_ENV) {
case 'production':
return {
...baseConfig,
enableLogging: false,
sessionTime: 86400,
}
case 'staging':
return {
...baseConfig,
enableLogging: true,
sessionTime: 3600,
}
default:
return {
...baseConfig,
enableLogging: true,
sessionTime: 1800,
}
}
}
getConfig() {
return this.config
}
updateConfig(updates) {
this.config = { ...this.config, ...updates }
}
}
// Usage
const configManager = new Web3AuthConfigManager()
const web3auth = new Web3Auth(configManager.getConfig())
Blockchain Integration
Web3Auth Node SDK supports multiple blockchain networks through different integration methods:
EVM Chains (Ethereum, Polygon, BSC, etc.)
Use the provider with ethers.js or convert to viem:
// With ethers.js
const { ethers } = require('ethers')
const ethProvider = new ethers.providers.Web3Provider(provider)
const signer = ethProvider.getSigner()
// Get private key directly
const privateKey = await provider.request({ method: 'eth_private_key' })
Solana Integration
Access Solana wallet functionality:
// Get Solana account info
const solanaWallet = await provider.request({ method: 'solanaWallet' })
const publicKey = solanaWallet.publicKey
// Get private key for Solana
const privateKey = await provider.request({ method: 'solanaPrivateKey' })
Other Blockchains
Access the raw private key for any blockchain integration:
// Get the raw private key
const privateKey = await provider.request({ method: 'private_key' })
// Use with your preferred blockchain library
// Example: Bitcoin, Cosmos, etc.
Key Features
Custom Authentication Only
The Node.js SDK only supports custom authentication. You must:
- Set up a custom verifier in the Web3Auth Dashboard
- Configure your authentication flow
- Generate valid ID tokens for users
- Use the verifier name and ID token in the connect method
Single Key Share
The SDK operates with a single key share, making it:
- Custodial: You have direct access to user private keys
- Stateless: No session state management required
- Backend-optimized: Perfect for server-side operations
Private Key Export
Private key export can be controlled through the Web3Auth Dashboard:
- Enable/disable private key export
- Control which methods return private keys
- Set up additional security measures
Security Considerations
Client ID Protection
- Store client ID in environment variables
- Use different client IDs for different environments
- Rotate client IDs regularly in production
Network Configuration
- Use
sapphire_mainnet
for production - Use
sapphire_devnet
for development and testing - Never use mainnet for testing
Session Management
- Set appropriate session timeouts
- Implement session cleanup
- Monitor for unusual session patterns
Next Steps
- Usage Guide: Learn about stateless authentication and blockchain operations
- Connect Method: Detailed authentication implementation
- Private Key Access: Extract keys for blockchain operations
- EVM Integration: Ethereum and EVM-compatible chains
- Examples: Complete implementation examples and production patterns
Troubleshooting
Bundler Issues: Missing Dependencies
You might encounter errors related to missing dependencies in the browser environment:
Buffer is not defined
process is not defined
- Other Node.js-specific modules missing errors
These Node.js dependencies need to be polyfilled in your application. We've prepared detailed troubleshooting guides for popular bundlers:
- Vite Troubleshooting Guide
- Svelte Troubleshooting Guide
- Nuxt Troubleshooting Guide
- Webpack 5 Troubleshooting Guide
JWT Errors
When using Custom Authentication, you may encounter JWT errors:
- Invalid JWT Verifiers ID field
- Failed to verify JWS signature
- Duplicate Token
- Expired Token
- Mismatch JWT Validation field
Usage Overview
The MetaMask Embedded Wallets Node.js SDK provides stateless authentication and blockchain operations for backend applications. Unlike frontend SDKs, this is designed for per-request authentication without persistent sessions.
Core Methods
Authentication & Connection
- connect - Authenticate users and establish provider connection (stateless)
Blockchain Operations
- Private Key Access - Extract private keys for blockchain operations
- EVM Integration - Work with Ethereum and EVM-compatible chains
Important Notes
Stateless Design
The Node.js SDK is stateless and sessionless by design:
- No persistent user sessions
- No
getUserInfo()
orlogout()
methods - Each request requires re-authentication
- Perfect for backend APIs and microservices
Common Usage Pattern
The typical flow when using the Node.js SDK:
const { Web3Auth } = require('@web3auth/node-sdk')
const { EthereumPrivateKeyProvider } = require('@web3auth/ethereum-provider')
// 1. Configure provider (once, during app startup)
const privateKeyProvider = new EthereumPrivateKeyProvider({
config: {
chainConfig: {
chainNamespace: 'eip155',
chainId: '0x1',
rpcTarget: 'https://rpc.ankr.com/eth',
},
},
})
// 2. Initialize Web3Auth (once, during app startup)
const web3auth = new Web3Auth({
clientId: 'YOUR_CLIENT_ID',
web3AuthNetwork: 'sapphire_mainnet',
privateKeyProvider,
})
await web3auth.init()
// 3. Connect user (per request)
const provider = await web3auth.connect({
verifier: 'YOUR_VERIFIER',
verifierId: 'user@example.com',
idToken: 'JWT_TOKEN',
})
// 4. Use provider for blockchain operations
const privateKey = await provider.request({ method: 'eth_private_key' })
// 5. Perform blockchain operations with preferred library
Error Handling
Always implement proper error handling when using the SDK:
try {
const provider = await web3auth.connect({
verifier: 'YOUR_VERIFIER',
verifierId: 'user@example.com',
idToken: 'JWT_TOKEN',
})
// Success - proceed with blockchain operations
const privateKey = await provider.request({ method: 'eth_private_key' })
} catch (error) {
console.error('Authentication failed:', error.message)
// Handle authentication errors
}
Best Practices
- Initialize once: Call
init()
during application startup, not per request - Stateless requests: Each user authentication is independent
- Handle errors: Always wrap SDK calls in try-catch blocks
- Secure storage: Protect private keys and never log them
- Rate limiting: Implement rate limiting for authentication endpoints
- Token validation: Validate JWT tokens before passing to connect method
- Provider reuse: Create providers once, reuse for multiple users