<!DOCTYPE html>
<html>
<head>
<title>Login with Ethereum</title>
<style>
body { background-color: #3f3f3f; color: #e2e2e2; font-family: sans-serif; display: flex; justify-content: center; align-items: center; height: 80vh; }
#login-button { padding: 15px 30px; font-size: 1.2em; cursor: pointer; }
#status { margin-top: 20px; color: red; }
</style>
</head>
<body>
<div>
<h1>Login with Ethereum</h1>
<button id="login-button">Connect Wallet & Sign In</button>
<p id="status"></p>
</div>
<script>
const statusElement = document.getElementById('status');
const loginButton = document.getElementById('login-button');
async function connectAndLogin() {
if (typeof window.ethereum === 'undefined') {
statusElement.textContent = 'MetaMask or other Web3 wallet not detected. Please install one.';
return;
}
statusElement.textContent = 'Connecting...';
try {
// Request account access
const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
const address = accounts[0]; // Use the first account
if (!address) {
statusElement.textContent = 'No Ethereum account selected.';
return;
}
statusElement.textContent = `Connected: ${address}. Generating message...`;
// *** IMPORTANT: Define the message to sign ***
// This message should ideally contain data like a nonce from the server
// to prevent replay attacks. For simplicity here, we use a static message + timestamp.
// A better approach: Backend provides a nonce via an API call.
const messageToSign = `Sign this message to authenticate with our service.\n\nAddress: ${address}\nTimestamp: ${new Date().toISOString()}`;
const msgParams = [address, messageToSign];
statusElement.textContent = 'Requesting signature...';
// Request signature
// Using personal_sign is generally preferred over eth_sign
const signature = await window.ethereum.request({
method: 'personal_sign',
params: msgParams,
});
statusElement.textContent = 'Signature received. Sending to backend...';
const nonceResponse = await fetch("/api/auth/web3/nonce");
const { nonce } = await nonceResponse.json();
// Send address, signature, and message to your backend API
const response = await fetch('/api/auth/web3/login/', { // Adjust URL if necessary
method: 'POST',
headers: {
'Content-Type': 'application/json',
// Include CSRF token for Django forms if applicable,
// but for a DRF API endpoint, it might not be needed
// if CSRF_USE_SESSIONS is False or you handle it differently.
// If needed: 'X-CSRFToken': getCookie('csrftoken'),
},
body: JSON.stringify({
address: address,
signature: signature,
message: messageToSign,
nonce
}),
});
if (response.ok) {
statusElement.textContent = 'Login successful!';
window.location.href = '/';
} else {
const errorData = await response.json();
statusElement.textContent = `Login failed: ${response.status} - ${JSON.stringify(errorData)}`;
console.error('Login error:', errorData);
}
} catch (error) {
statusElement.textContent = `Operation cancelled or failed: ${error.message}`;
console.error('Web3 operation error:', error);
}
}
loginButton.addEventListener('click', connectAndLogin);
// Helper to get CSRF token if needed for Django forms
// function getCookie(name) {
// let cookieValue = null;
// if (document.cookie && document.cookie !== '') {
// const cookies = document.cookie.split(';');
// for (let i = 0; i < cookies.length; i++) {
// const cookie = cookies[i].trim();
// // Does this cookie string begin with the name we want?
// if (cookie.substring(0, name.length + 1) === (name + '=')) {
// cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
// break;
// }
// }
// }
// return cookieValue;
// }
</script>
</body>
</html>
Login with Ethereum
Login with Ethereum
Connect Wallet & Sign In