Autentikasi di Ethereum
Jika Anda berasal dari pengembangan web tradisional, Anda terbiasa dengan login nama pengguna/kata sandi, alur OAuth, dan kuki sesi. Autentikasi di Ethereum bekerja secara berbeda—dan dalam banyak hal, lebih sederhana.
Di Ethereum, pengguna membuktikan identitas mereka dengan menandatangani pesan dengan dompet mereka. Tidak ada kata sandi yang perlu disimpan. Tidak ada basis data kredensial yang bisa bocor. Hanya kriptografi.
Apa bedanya dengan Web2?
| Web2 | Ethereum |
|---|---|
| Nama pengguna + kata sandi | Alamat dompet + tanda tangan |
| Server menyimpan kredensial | Pengguna memegang kunci privat |
| Sesi dikelola oleh kuki / JWT | Sesi dimulai dengan tanda tangan dompet offchain |
| "Masuk dengan Google" | "Masuk dengan Ethereum" |
| Alur pengaturan ulang kata sandi | Pemulihan frasa benih |
Perubahan mendasarnya: di Web2, server terpusat mengautentikasi Anda. Di Ethereum, Anda mengautentikasi diri sendiri dengan membuktikan bahwa Anda mengendalikan alamat tertentu—dan siapa pun dapat memverifikasinya secara independen.
Prasyarat
Pastikan Anda memahami:
- Akun Ethereum dan cara kerjanya
- Apa itu dompet dan cara menghubungkannya
- Dasar-dasar kriptografi kunci publik-privat
Cara kerja autentikasi berbasis dompet
Alur intinya sederhana:
- Aplikasi terdesentralisasi (dapp) Anda meminta pengguna untuk menghubungkan dompet mereka (melalui MetaMask, Rainbow, WalletConnect, dll.)
- Dompet membagikan alamat Ethereum pengguna - ini adalah pengidentifikasi publik mereka
- Dapp Anda menghasilkan pesan unik (sebuah nonce atau tantangan)
- Pengguna menandatangani pesan dengan kunci privat mereka (terjadi di dalam dompet)
- Backend Anda memverifikasi tanda tangan terhadap alamat yang diklaim
- Jika valid, pengguna diautentikasi
Tidak ada kata sandi yang pernah diketik, disimpan, atau dikirimkan.
Masuk dengan Ethereum (EIP-4361)
EIP-4361 (terbuka di tab baru) mendefinisikan format pesan standar untuk masuk dengan Ethereum, yang umumnya disebut SIWE (Sign-In with Ethereum). Ini menggantikan penandatanganan pesan ad-hoc dengan standar yang terstruktur dan aman.
Pesan SIWE terlihat seperti ini:
example.com wants you to sign in with your Ethereum account:
0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B
I accept the Terms of Service: https://example.com/tos
URI: https://example.com/login
Version: 1
Chain ID: 1
Nonce: 32891757
Issued At: 2024-06-12T14:30:00Z
Fitur utama SIWE:
- Pengikatan domain - pesan menyertakan domain, mencegah phishing
- ID Rantai - menentukan jaringan mana tanda tangan tersebut valid
- Nonce - mencegah serangan pemutaran ulang (replay attacks)
- Kedaluwarsa - stempel waktu opsional yang membatasi jendela validitas
- Sumber daya - URI opsional untuk akses dengan cakupan tertentu
Pustaka SIWE
- siwe (terbuka di tab baru) - Implementasi resmi TypeScript oleh Spruce
- siwe-rs (terbuka di tab baru) - Implementasi Rust
- siwe-go (terbuka di tab baru) - Implementasi Go
Contoh: masuk sisi klien dengan siwe
import { SiweMessage } from 'siwe'
import { BrowserProvider } from 'ethers'
async function signIn() {
const provider = new BrowserProvider(window.ethereum)
const signer = await provider.getSigner()
const address = await signer.getAddress()
// 1. Dapatkan nonce dari backend Anda
const { nonce } = await fetch('/api/auth/nonce').then(r => r.json())
// 2. Buat dan tandatangani pesan SIWE
const message = new SiweMessage({
domain: window.location.host,
address,
statement: 'Sign in to My Dapp',
uri: window.location.origin,
version: '1',
chainId: 1,
nonce,
})
const signature = await signer.signMessage(message.prepareMessage())
// 3. Kirim ke backend untuk verifikasi
await fetch('/api/auth/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message, signature }),
})
}
Contoh: verifikasi sisi server (Node.js)
import { SiweMessage, generateNonce } from 'siwe'
// Keluarkan nonce dan simpan di sesi sehingga /verify dapat memeriksanya nanti
app.get('/api/auth/nonce', (req, res) => {
req.session.nonce = generateNonce()
res.json({ nonce: req.session.nonce })
})
app.post('/api/auth/verify', async (req, res) => {
try {
const { message, signature } = req.body
const siweMessage = new SiweMessage(message)
const { success, data } = await siweMessage.verify({
signature,
nonce: req.session.nonce,
})
if (success) {
// data.address adalah alamat Ethereum yang terverifikasi
// Buat sesi atau JWT untuk pengguna
req.session.address = data.address
res.json({ ok: true, address: data.address })
}
} catch {
res.status(401).json({ error: 'Invalid signature' })
}
})
Pustaka koneksi dompet
Sebelum mengautentikasi, Anda perlu pengguna untuk menghubungkan dompet mereka. Pustaka-pustaka ini membuatnya mudah:
- RainbowKit (terbuka di tab baru) - Komponen React siap pakai dengan UI yang indah
- ConnectKit (terbuka di tab baru) - Modal koneksi dompet drop-in
- AppKit (WalletConnect) (terbuka di tab baru) - Koneksi dompet multirantai dengan SIWE bawaan
- Wagmi (terbuka di tab baru) - Pustaka React Hooks dengan
useAccount,useConnect
Memverifikasi tanda tangan secara manual
Jika Anda lebih suka tidak menggunakan SIWE, Anda dapat memverifikasi tanda tangan secara langsung:
import { verifyMessage } from 'ethers'
// Pesan yang ditandatangani pengguna
const message = `Sign in to My Dapp. Nonce: ${storedNonce}`
// Pulihkan alamat penandatangan dari tanda tangan
const recoveredAddress = verifyMessage(message, signature)
// Bandingkan dengan alamat yang diklaim
if (recoveredAddress.toLowerCase() === claimedAddress.toLowerCase()) {
// Autentikasi berhasil
}
Catatan keamanan penting
- Selalu gunakan nonce - mencegah serangan pemutaran ulang di mana tanda tangan lama digunakan kembali
- Sertakan domain - mencegah tanda tangan menjadi valid di berbagai situs yang berbeda
- Periksa kedaluwarsa - tanda tangan harus memiliki jendela validitas yang terbatas
- Gunakan SIWE (EIP-4361) jika memungkinkan - ini menangani semua hal di atas untuk Anda
- Jangan pernah mengekspos kunci privat - penandatanganan terjadi di dalam dompet; aplikasi Anda hanya melihat hasilnya
Manajemen sesi
Setelah diautentikasi, Anda masih memerlukan sesi—sama seperti Web2. Pola umum:
- Token JWT - terbitkan JWT setelah memverifikasi tanda tangan, gunakan untuk permintaan API
- Sesi sisi server - simpan alamat yang diverifikasi dalam kuki sesi
- SIWE dengan sumber daya - tentukan token akses dengan cakupan yang ditautkan ke URI tertentu
Perbedaan utama dari Web2: alamat Ethereum pengguna adalah identitas persisten mereka. Mereka dapat menggunakannya di seluruh dapp mana pun tanpa membuat akun baru.
Identitas terdesentralisasi
Autentikasi Ethereum adalah bagian dari gerakan yang lebih luas menuju identitas berdaulat sendiri (self-sovereign identity). Standar dan proyek di ruang ini meliputi:
- Ethereum Name Service (ENS) (terbuka di tab baru) - Nama yang dapat dibaca manusia (misalnya,
vitalik.eth) yang diselesaikan menjadi alamat - Ethereum Attestation Service (EAS) (terbuka di tab baru) - Atestasi onchain tentang identitas dan kredensial
- W3C Decentralized Identifiers (DIDs) (terbuka di tab baru) - Standar global untuk identitas terdesentralisasi (DID) yang dapat diverifikasi
- Ceramic Network (terbuka di tab baru) - Aliran data terdesentralisasi yang terikat pada sebuah DID
Bacaan lebih lanjut
- EIP-4361: Masuk dengan Ethereum (terbuka di tab baru)
- Dokumentasi SIWE (terbuka di tab baru)
- Masuk dengan Ethereum di Auth0 (terbuka di tab baru)
- Dokumentasi autentikasi Reown AppKit (terbuka di tab baru)
- Dokumentasi ENS (terbuka di tab baru)