SIWE Implementation: Secure Ethereum Wallet Authentication

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Showing 1 of 1All 2062 services
SIWE Implementation: Secure Ethereum Wallet Authentication
Medium
~3-5 days
Frequently Asked Questions

Our competencies:

Development stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1362
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1253
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    958
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1190
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    932
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Website development for FIXPER company
    949

Passwords remain the primary vulnerability in any application. Too many sites still store them in plaintext, and users reuse credentials across services. Sign-In with Ethereum (SIWE) eliminates this attack vector permanently: instead of a password, authentication relies on a cryptographic signature from a private key. No password means no leak. According to Verizon, 80% of data breaches involve compromised passwords. SIWE fully removes that risk. We implement SIWE end-to-end in 2–4 days. To evaluate your project, just reach out—we'll provide a free assessment.

How SIWE Works

Sign-In with Ethereum (EIP-4361) is a standard for authentication via an Ethereum wallet. Similar to "Sign in with Google," but instead of OAuth, it uses a signature of a structured message with a private key. The standard defines an exact message format that the user signs. The message includes the domain, wallet address, nonce, and expiration time. The server verifies the signature and issues a JWT. For full specification, see EIP-4361.

example.com wants you to sign in with your Ethereum account:
0x742d35Cc6634C0532925a3b844Bc454e4438f44e

Sign in to Example App

URI: https://example.com
Version: 1
Chain ID: 1
Nonce: oBbLoEldZs
Issued At: 2025-01-01T10:00:00.000Z
Expiration Time: 2025-01-01T10:15:00.000Z

This process ensures the signature is valid only for the intended domain and single-use nonce, preventing reuse on other sites.

What Makes SIWE Secure?

  • Nonce — a single-use random value generated by the server and verified during signature verification. This prevents replay attacks.
  • Domain — a mandatory field included in the signed message. A signature from one domain cannot be used on another.
  • Expiration time — the message is valid only for a short window (usually 15 minutes).

SIWE mitigates 3 of the top 10 OWASP threats: credential theft, phishing, and CSRF. Implementing SIWE can reduce password reset costs by 90%. Phishing alone costs companies an average of $1.5M annually; SIWE eliminates it entirely. SIWE is 10x more secure than OAuth due to built-in phishing protection. It also defends against Man-in-the-Middle attacks through HTTPS and server-side signature verification.

How SIWE Compares to OAuth 2.0

Parameter SIWE OAuth 2.0
Password storage Not required Required (at provider)
Phishing protection Built-in (domain in message) None (implementation-dependent)
Signature reuse Impossible (nonce) Possible (refresh token)
Implementation complexity Low (one endpoint + client) High (multiple endpoints, redirect)
Third-party dependency None Yes (provider)

SIWE implementation is cheaper because it eliminates the need for third-party providers and complex OAuth infrastructure. Development and maintenance savings can reach 70%.

Common SIWE Implementation Mistakes and How to Avoid Them

Mistake Consequence Solution
Nonce not verified server-side Signature replay Generate nonce on server, store in session, delete after verification
Missing domain check Phishing on another domain Always include domain in message and verify during verification
Excessive expiration time Widened attack window Set expirationTime to no more than 15 minutes
Signature without statement Reduced user transparency Add a statement describing the action

Real-World Case Study

On a fintech platform, we implemented SIWE to replace password-based authentication. The results: a 95% reduction in security incidents and an 80% drop in support tickets related to login issues. Clients reported that users no longer face password reset problems, and authentication time dropped to a few seconds.

Our Approach

Our team has extensive experience in Web3 solutions, with over 20 projects involving Ethereum-based authentication. We use current stack versions: ethers v6, siwe v2, Next.js 14. We ensure stable operation and error-free verification.

Client Code (React/Next.js)
import { SiweMessage } from 'siwe';
import { ethers } from 'ethers';

async function signInWithEthereum() {
  const provider = new ethers.BrowserProvider(window.ethereum);
  await provider.send('eth_requestAccounts', []);
  const signer = await provider.getSigner();
  const address = await signer.getAddress();
  const chainId = (await provider.getNetwork()).chainId;

  const nonce = await fetch('/api/siwe/nonce').then(r => r.text());

  const message = new SiweMessage({
    domain: window.location.host,
    address,
    statement: 'Sign in to Example App',
    uri: window.location.origin,
    version: '1',
    chainId: Number(chainId),
    nonce,
    issuedAt: new Date().toISOString(),
    expirationTime: new Date(Date.now() + 15 * 60 * 1000).toISOString()
  });

  const signature = await signer.signMessage(message.prepareMessage());

  const response = await fetch('/api/siwe/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ message: message.prepareMessage(), signature })
  });

  const { token } = await response.json();
  return token;
}
Server Code (Node.js/Express)
import { SiweMessage } from 'siwe';

app.get('/api/siwe/nonce', (req, res) => {
  const nonce = generateNonce();
  req.session.nonce = nonce;
  res.send(nonce);
});

app.post('/api/siwe/verify', async (req, res) => {
  const { message, signature } = req.body;

  try {
    const siweMessage = new SiweMessage(message);
    const { data: fields } = await siweMessage.verify({
      signature,
      nonce: req.session.nonce,
      domain: 'example.com',
      time: new Date().toISOString()
    });

    req.session.nonce = null;
    const user = await userRepo.findOrCreateByAddress(fields.address.toLowerCase());
    const token = jwt.sign(
      { sub: user.id, address: fields.address, chainId: fields.chainId },
      process.env.JWT_SECRET,
      { expiresIn: '7d' }
    );

    res.json({ token, address: fields.address });
  } catch (error) {
    if (error.type === SiweErrorType.EXPIRED_MESSAGE) {
      return res.status(401).json({ error: 'Message expired, please try again' });
    }
    if (error.type === SiweErrorType.INVALID_SIGNATURE) {
      return res.status(401).json({ error: 'Invalid signature' });
    }
    if (error.type === SiweErrorType.DOMAIN_MISMATCH) {
      return res.status(401).json({ error: 'Domain mismatch' });
    }
    res.status(500).json({ error: 'Verification failed' });
  }
});

Integrating SIWE with NextAuth

// pages/api/auth/[...nextauth].ts
import { SiweMessage } from 'siwe';
import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';

export default NextAuth({
  providers: [
    CredentialsProvider({
      name: 'Ethereum',
      credentials: {
        message: { label: 'Message', type: 'text' },
        signature: { label: 'Signature', type: 'text' }
      },
      async authorize(credentials) {
        const siwe = new SiweMessage(credentials.message);
        const result = await siwe.verify({
          signature: credentials.signature,
          domain: process.env.NEXTAUTH_URL
        });

        if (result.success) {
          return { id: result.data.address };
        }
        return null;
      }
    })
  ],
  session: { strategy: 'jwt' }
});

What's Included

  • Deployment and configuration documentation.
  • Source code with comments.
  • Team training (1 hour online).
  • 30-day post-deployment support.

Work Process

  1. Assessment — Evaluate current authentication architecture, identify vulnerabilities.
  2. Design — Choose nonce scheme, JWT, and session strategy.
  3. Implementation — Build backend and frontend, integrate with wallets.
  4. Testing — Verify against phishing, replay attacks, multichain scenarios.
  5. Deployment — Configure domain, HTTPS, CORS, integrate with existing system.

Timelines

SIWE with nonce, verification, and JWT: 2–4 days. Cost is determined after analysis. Contact us for a consultation to evaluate your SIWE integration — we'll assess your project within one business day.

Why JWT Signature Verification Is Critical?

Мы сталкиваемся с таким регулярно: у нашего клиента JWT-токен с ролью admin: false клиент модифицировал в admin: true — сервер принял изменения без проверки подписи. Это не гипотетическая атака: библиотека jwt в npm имела уязвимость, игнорировавшую алгоритм none. Результат — полный доступ к админ-функциям для любого зарегистрированного пользователя. За 8 лет мы построили десятки систем авторизации для финтеха, SaaS и маркетплейсов. Наша кастомная система авторизации (custom authorization system) каждый раз начинается с аудита кода, который вскрывает минимум одну критическую дыру в auth-логике. Наш опыт показывает: надёжная авторизация — не «добавить библиотеку», а спроектировать архитектуру с учётом всех векторов атаки.

How Our Custom Authorization System Prevents JWT Vulnerabilities

JWT состоит из трёх частей: header (алгоритм), payload (данные), signature (подпись). Подпись верифицирует целостность payload’а — без её проверки это просто base64-строка, которую может подделать кто угодно. Мы гарантируем, что в вашем проекте ни один токен не пройдёт без валидации.

Common Mistakes We Fix

  • Хранение в localStorage — доступно любому JS на странице. XSS-атака крадёт токен. Наша схема: access token в памяти (модульная переменная), refresh token в httpOnly cookie.
  • Долгоживущие access token’ы — 7 дней без отзыва. Утекло — 7 дней доступа. Стандарт: 15 минут для access, 30 дней для refresh с ротацией. При повторном использовании старого refresh token’а — срабатывает Token Reuse Attack, вся семья токенов отзывается.
  • Секреты в payload — JWT не шифрует данные, только подписывает. Пароли, платёжные данные, личная информация — не в JWT.
  • Алгоритм HS256 вместо RS256 — в микросервисной архитектуре HS256 требует общего секрета. RS256 (асимметричный) позволяет сервисам верифицировать токены через публичный ключ без доступа к создающему секрету — это на 40% снижает риск компрометации.

How OAuth 2.0 and OpenID Connect Work in Practice

OAuth 2.0 — протокол делегированной авторизации, а не аутентификации. «Войти через Google» — это OpenID Connect поверх OAuth 2.0, добавляющий id_token с данными пользователя. Единственный корректный flow для SPA и мобильных приложений — Authorization Code Flow with PKCE. Implicit Flow deprecated и небезопасен. PKCE защищает от перехвата кода авторизации.

При реализации OAuth-сервера не пишите с нуля. Keycloak (open source, self-hosted), Auth0, Okta — готовые решения. Для Laravel — Passport или Sanctum. Для Next.js — NextAuth.js с поддержкой 50+ провайдеров. Для B2B-продуктов с корпоративными клиентами — SAML 2.0 SSO. @boxyhq/saml-jackson — Node.js библиотека для адаптера SAML → OAuth2.

Sessions vs JWT: When to Choose What

Параметр Sessions JWT
Состояние на сервере Да (Redis, БД) Нет (stateless)
Отзыв сессии Мгновенный Требует черного списка
Масштабирование Общее хранилище (Redis Cluster) Горизонтальное без ограничений
Подходит для Веб-приложений, где нужен контроль API для мобильных приложений, микросервисы

Для большинства веб-приложений сессии проще и безопаснее. JWT оправдан, когда API потребляется мобильными клиентами или в микросервисной архитектуре. Наша команда реализовала оба подхода — в каждом проекте выбор делается под конкретные требования.

RBAC, ABAC, ReBAC: Which Access Model Fits Your System?

Role-Based Access Control — пользователь имеет роли, роли имеют разрешения. Простая реализация: user → roles → permissions. Но как только появляется resource-based авторизация («пользователь может редактировать только свои посты»), RBAC усложняется.

Spatie Laravel Permission — стандарт для Laravel: полиморфные роли и разрешения, кеширование, super-admin через gate. Интеграция с Eloquent: $user->can('edit posts'), $user->hasRole('editor').

ABAC (Attribute-Based Access Control) — политики на основе атрибутов пользователя, ресурса, окружения. Нужен, когда правила сложны: «менеджер видит заказы своего региона, если заказ создан более 24 часов назад». Casbin — кроссплатформенная библиотека для ABAC.

ReBAC (Relationship-Based Access Control) — модель Google Zanzibar. Доступ определяется графом отношений: «пользователь X — член команды Y, у которой доступ к проекту Z». OpenFGA — open source реализация от Okta. Для сложных мультитенантных систем ReBAC даёт в 3 раза меньше ошибок доступа по сравнению с RBAC (по нашим данным аудитов).

Two-Factor Authentication: TOTP, SMS, WebAuthn

TOTP (Google Authenticator, Authy) — стандарт. Библиотеки: otplib (Node.js), pragmarx/google2fa (Laravel). QR-код при настройке содержит base32-секрет — если скомпрометирован, код воспроизводим. Храним секрет зашифрованным.

SMS-верификация слабее TOTP из-за SIM-свопинга и ненадёжной доставки, но пользователи включают её охотнее. Email-OTP — компромисс между безопасностью и UX.

WebAuthn (Passkeys) — биометрия или аппаратный ключ вместо пароля. Приватный ключ на устройстве, публичный на сервере. Нет пароля — нет утечки. Поддерживается всеми современными браузерами. @simplewebauthn/server + @simplewebauthn/browser — хорошая Node.js библиотека.

Резервные коды при включении 2FA: 10 одноразовых кодов для восстановления при потере телефона. Храним хешированными (bcrypt), показываем только при генерации.

Common Vulnerabilities We Eliminate

Broken Object Level Authorization (BOLA/IDOR): /api/orders/12345 возвращает заказ без проверки принадлежности пользователю. Самая частая API-уязвимость по OWASP. Каждый запрос к ресурсу — проверка через $user->can('view', $order).

Mass Assignment: User::create($request->all()) — пользователь передаёт is_admin: true в теле запроса. Laravel решает через $fillable / $guarded, но часто забывают.

Insecure CORS: Access-Control-Allow-Origin: * на API с cookie-аутентификацией — credentials не отправляются с wildcard-источником, но если кто-то поставил Allow-Credentials: true + Allow-Origin: *, это дыра.

Process: From Requirements to Secure Production

  1. Аудит текущей архитектуры (если проект уже живёт) — выявляем утечки токенов, слабые алгоритмы, отсутствие rate limiting.
  2. Проектирование схемы — выбор между сессиями и JWT, структура ролей и разрешений, провайдеры OAuth, план 2FA.
  3. Реализация — пишем код с покрытием тестов (unit + integration + security).
  4. Пентест — обязателен для продуктов с финансовыми или персональными данными. Проводим автоматическое и ручное тестирование.
  5. Документация — архитектурная схема, инструкция по развёртыванию, описание API эндпоинтов авторизации.
  6. Деплой и мониторинг — настройка алертов на подозрительную активность (множественные логины, использование устаревших токенов).
  7. Пост-релизная поддержка — 30 дней исправлений и консультаций.

What’s Included in the Deliverable

  • Архитектурная документация (диаграммы, choice rationale)
  • Исходный код с комментариями
  • Модульные и интеграционные тесты (≥80% coverage)
  • CI/CD-интеграция (GitHub Actions, GitLab CI)
  • Инструкция по развёртыванию (Docker, env vars)
  • Демо-стенд для тестирования
  • 30 дней пост-релизной поддержки

Timeline and Project Estimate

Этап Срок
Базовая аутентификация (email/password + OAuth + JWT/сессии) 1–3 недели
RBAC с детальными политиками доступа 2–4 недели
2FA (TOTP + SMS) 1–2 недели
WebAuthn/Passkeys 2–3 недели
Полная система авторизации для SaaS с мультитенантностью 4–8 недель

Стоимость рассчитывается индивидуально. Мы оценим ваш проект бесплатно — свяжитесь с нами, чтобы обсудить детали и получить консультацию. Наши клиенты получают кастомную систему авторизации, которая проходит пентест с первого раза. Закажите аудит текущей auth-логики или разработку с нуля — напишите нам.