Saludos Hivers, por aca les traigo una nueva entrega para seguir con los tutoriales de Hive & React. En este articulo veremos como crear algo en el reino de lo que llamamos Fullstack y trata de como autenticar usando Hive Keychain.
Link al repositorio principal del tutorial completo >> aqui <<
🧩 Proceso de Inicio de Sesión con Hive Keychain
Instalación de Hive Keychain
El usuario instala la extensión Hive Keychain en su navegador compatible.Importación de la Cuenta Hive
Se importan las claves privadas del usuario en la extensión para habilitar la firma de transacciones.Interfaz de Inicio de Sesión
La aplicación presenta un botón o formulario para que el usuario inicie sesión con su nombre de usuario de Hive.Generación de Mensaje Único
La aplicación genera un mensaje único, como una marca de tiempo, para prevenir ataques de repetición.Solicitud de Firma con Hive Keychain
Se utiliza la función requestSignBuffer para solicitar al usuario que firme el mensaje a través de Hive Keychain.Firma del Mensaje
El usuario aprueba la solicitud en la extensión, que firma el mensaje con su clave privada de publicación.Envío al Servidor para Verificación
La aplicación envía el nombre de usuario, el mensaje y la firma al servidor backend para su verificación.Obtención de Clave Pública desde la Blockchain
El servidor recupera la clave pública de publicación del usuario desde la blockchain de Hive.Verificación de la Firma
El servidor utiliza la clave pública para verificar que la firma corresponde al mensaje original.Confirmación de Autenticación Exitosa
Si la firma es válida, el servidor responde afirmativamente, y el usuario es considerado autenticado.
Este proceso garantiza una autenticación segura y descentralizada sin necesidad de compartir contraseñas o claves privadas directamente con la aplicación.
English at the bottom
Frontend: Cliente
🛠️ Configuración del Proyecto
- Crear el Proyecto con Vite
- Creamos la carpeta para el client y nos movemos a la carpeta:
mkdir client && cd client
- Ejecuta el siguiente comando para crear un nuevo proyecto con Vite y React utilizando TypeScript:
npm create vite@latest . -- --template react-ts
Instalar Dependencias Adicionales
- Instalemos keychain-helper para ayudarnos a interactuar con la Hive Keychain
npm i keychain-helper
- Creamos una carpeta dentro de
/src/
y la llamamoscomponents
y dentro creamos el archivo Login.tsx:
import React from 'react';
import {KeychainHelper} from 'keychain-helper';
const Login: React.FC = () => {
const handleLogin = async () => {
const username = prompt('Ingrese su nombre de usuario de Hive:');
if (!username) return;
const message = `Autenticación con Hive Keychain - ${new Date().toISOString()}`;
KeychainHelper.requestLogin(username,message, async (keychainResponse) => {
if(keychainResponse.success){
//continue to send info to backend for verification.
const responseBE = await fetch('http://localhost:6001/verify', {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username, message, signature: keychainResponse.result
}),
});
if(responseBE.status === 200){ //{ success: true, message: 'Firma válida' }
const result = await responseBE.json();
if(result.success && result.message === "Firma válida"){
alert('Autenticado con exito! Ahora puedes codificar las rutas protegidas y demas!');
}else{
console.log('No se autentico: ',{result});
}
}
}else{
console.log({keychainResponse});
}
});
};
return (
<div>
<h2>Iniciar Sesión con Hive Keychain</h2>
<button onClick={handleLogin}>Iniciar Sesión</button>
</div>
);
};
export default Login;
- Usamos login en App.tsx y podemos remover todo el codigo por defecto, nos quedaria asi:
import './App.css'
import Login from './components/Login'
function App() {
return (
<>
<Login />
</>
)
}
export default App
- Iniciamos la App(Ojo el servidor ya debe estar corriendo) y usamos:
npm run dev
- Deberias ver algo como esto al ejecutar tu frontend:
Nota: Hive Keychain debe estar instalado para poder interactuar con la firma del mensaje. Mas info aca: https://hive-keychain.com/
Backend: servidor
Nota importante: siempre que veas una linea de comandos con multiples comandos, puedes ejecutar 1 por una y asi sabras lo que cada una hace o simplemente corre todo a la vez.
🔐 Implementación del Backend
- Configurar el Servidor con Express
- Ejecutamos uno a uno, estos comandos si iniciamos el proyecto desde cero:
mkdir server
cd server
npm init -y
npm install express@^4.17.1 cors body-parser dhive
npm install --save-dev typescript @types/express@^4.17.13 @types/node @types/body-parser ts-node nodemon @types/cors
Lo que hicimos fue:
- Crear el directorio server
- Nos movemos a server
- Inicializamos usando npm, eso nos crea un archivo package.json con la informacion por defecto
- Instalamos dependencias para express que hacen:
- cors(que nos permite probar el servidor localmente sin uso de https)
- body-parser(procesar los datos enviados en el "cuerpo" de las peticiones HTTP entrantes)
- dhive(libreria para interactuar con la HIVE blockchain y funciones utiles)
- Instalamos ademas dependencias de desarrollo que son tipos y declaraciones necesarias para typescript.
Nota decidi dejar esas versiones para express y sus tipos ya que para versiones mas recientes a veces causa errores en desarrollo.
- Crea un archivo tsconfig.json en la carpeta server con la configuración básica de TypeScript.
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "dist",
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
}
Implementar la Ruta de Verificación
En el archivo server/index.ts, implementa una ruta para verificar la firma:
import express, {Request,Response} from 'express';
import cors from 'cors';
import bodyParser from 'body-parser';
import { Client, PublicKey, Signature, cryptoUtils } from '@hiveio/dhive';
const app = express();
app.use(cors());
app.use(bodyParser.json());
const client = new Client(['https://api.hive.blog']);
app.post('/verify', async (req: Request, res: Response) => {
// Datos recibidos del cliente
const { username, message, signature: signatureStr } = req.body;
try {
// Obtener la clave pública del usuario desde la blockchain
const account = await client.database.getAccounts([username]);
if (!account || account.length === 0) {
return res.status(404).json({ error: 'Usuario no encontrado' });
}
const publicKeyData = account[0].posting.key_auths[0][0];
const publicKeyStr = typeof publicKeyData === 'string' ? publicKeyData : publicKeyData.toString();
// Crear instancias de PublicKey y Signature
const publicKey = PublicKey.fromString(publicKeyStr);
const signature = Signature.fromString(signatureStr);
// Calcular el hash del mensaje
const messageHash = cryptoUtils.sha256(message);
// Verificar la firma
const isValid = publicKey.verify(messageHash, signature);
if (isValid) {
res.status(200).json({ success: true, message: 'Firma válida' });
} else {
res.status(401).json({ success: false, message: 'Firma inválida' });
}
} catch (error) {
console.error('Error al verificar la firma:', error);
res.status(500).json({ error: 'Error interno del servidor' });
}
});
app.listen(6001, () => {
console.log('Servidor backend ejecutándose en http://localhost:6001');
});
🧪 Prueba/Puesta en marcha de la Aplicación
- Ejecuta
npx ts-node index.ts
Deberias ver algo como esto en tu consola de VSCode:
Pro-tip
Siempre inicia el backend primero. No necesitas abrir varios editores de VScode, simpelemte, debajo en la seccion de terminales abre al menos 2. Y vas navegando usando los comandos ls
cd
para moverte a la carpeta client y al server.
De esta manera puede ejecutar cada parte en una consola por separado.
Si todo marcha como debería, al hacer login sucedera esto:
English Version Here
Greetings Hivers, here I bring you a new installment to continue with the Hive & React tutorials. In this article, we will explore creating something in the realm of what we call Fullstack, focusing on authentication using Hive Keychain.
Frontend: Client
Certainly! Here's the translated and formatted markdown content for the login process using Hive Keychain:
🧩 Hive Keychain Login Process
Install Hive Keychain Extension
The user installs the Hive Keychain extension on a compatible browser (e.g., Chrome, Firefox).Import Hive Account
The user imports their Hive account into the extension using the "Use keys/pwd" option.Enter Hive Credentials
The user enters their Hive username and master password to import their keys.Set Up Keychain Password
The user sets a unique password for the Hive Keychain extension on their device.Access dApp Login Interface
The user navigates to the decentralized application's login interface that supports Hive Keychain.Initiate Login Request
The dApp prompts the user to log in, triggering Hive Keychain to open a signature request.Sign Authentication Message
The user reviews and signs the authentication message using their posting key via Hive Keychain.Send Signature to Backend
The dApp sends the signed message and username to the backend server for verification.Verify Signature on Server
The backend retrieves the user's public key from the Hive blockchain and verifies the signature.Confirm Successful Authentication
If the signature is valid, the server confirms authentication, granting the user access to the dApp.
This process ensures secure and decentralized authentication without exposing private keys or passwords.
🛠️ Project Setup
Create the Project with Vite
Create the folder for the client and navigate into it:
mkdir client && cd client
Run the following command to create a new project with Vite and React using TypeScript:
npm create vite@latest . -- --template react-ts
Install Additional Dependencies
Install
keychain-helper
to assist in interacting with Hive Keychain:npm i keychain-helper
Create a folder inside
/src/
namedcomponents
and within it, create the fileLogin.tsx
:import React from 'react'; import { KeychainHelper } from 'keychain-helper'; const Login: React.FC = () => { const handleLogin = async () => { const username = prompt('Enter your Hive username:'); if (!username) return; const message = `Authentication with Hive Keychain - ${new Date().toISOString()}`; KeychainHelper.requestLogin(username, message, async (keychainResponse) => { if (keychainResponse.success) { // Continue to send info to backend for verification. const responseBE = await fetch('http://localhost:6001/verify', { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ username, message, signature: keychainResponse.result }), }); if (responseBE.status === 200) { const result = await responseBE.json(); if (result.success && result.message === "Valid signature") { alert('Successfully authenticated! Now you can code protected routes and more!'); } else { console.log('Authentication failed: ', { result }); } } } else { console.log({ keychainResponse }); } }); }; return ( <div> <h2>Log In with Hive Keychain</h2> <button onClick={handleLogin}>Log In</button> </div> ); }; export default Login;
Use the
Login
component inApp.tsx
and remove all default code, resulting in:import './App.css' import Login from './components/Login' function App() { return ( <> <Login /> </> ) } export default App
Start the App (ensure the server is already running) using:
npm run dev
Note: Hive Keychain must be installed to interact with message signing. More info here: https://hive-keychain.com/
Backend: Server
Important Note: Whenever you see a command line with multiple commands, you can execute them one by one to understand what each does, or simply run them all at once.
🔐 Backend Implementation
Set up the Server with Express
Execute the following commands one by one if starting the project from scratch:
mkdir server cd server npm init -y npm install express@^4.17.1 cors body-parser dhive npm install --save-dev typescript @types/express@^4.17.13 @types/node @types/body-parser ts-node nodemon @types/cors
What we did:
Created the
server
directoryNavigated into
server
Initialized with npm, creating a
package.json
file with default informationInstalled dependencies for Express:
cors
(allows us to test the server locally without using HTTPS)body-parser
(processes data sent in the body of incoming HTTP requests)dhive
(library to interact with the HIVE blockchain and useful functions)
Additionally installed development dependencies which are types and declarations necessary for TypeScript.
Note: I chose to use these versions for Express and its types because newer versions sometimes cause development errors.
Create a
tsconfig.json
file in theserver
folder with the basic TypeScript configuration:{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "outDir": "dist", "rootDir": "src", "strict": true, "esModuleInterop": true, "skipLibCheck": true } }
Implement the Verification Route
In the file server/index.ts
, implement a route to verify the signature:
import express, { Request, Response } from 'express';
import cors from 'cors';
import bodyParser from 'body-parser';
import { Client, PublicKey, Signature, cryptoUtils } from '@hiveio/dhive';
const app = express();
app.use(cors());
app.use(bodyParser.json());
const client = new Client(['https://api.hive.blog']);
app.post('/verify', async (req: Request, res: Response) => {
const { username, message, signature: signatureStr } = req.body;
try {
const account = await client.database.getAccounts([username]);
if (!account || account.length === 0) {
return res.status(404).json({ error: 'User not found' });
}
const publicKeyData = account[0].posting.key_auths[0][0];
const publicKeyStr = typeof publicKeyData === 'string' ? publicKeyData : publicKeyData.toString();
const publicKey = PublicKey.fromString(publicKeyStr);
const signature = Signature.fromString(signatureStr);
const messageHash = cryptoUtils.sha256(message);
const isValid = publicKey.verify(messageHash, signature);
if (isValid) {
res.status(200).json({ success: true, message: 'Valid signature' });
} else {
res.status(401).json({ success: false, message: 'Invalid signature' });
}
} catch (error) {
console.error('Error verifying signature:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
app.listen(6001, () => {
console.log('Backend server running at http://localhost:6001');
});
🧪 Testing/Launching the Application
Run:
npx ts-node index.ts
Pro-tip
Always start the backend first. You don't need to open multiple VSCode editors; simply open at least two terminals in the terminal section below. Navigate using the commands ls
and cd
to move to the client
and server
folders respectively.
This way, you can run each part in a separate console.
keychain already checked the signature when it returned a success message, why do you check again in the backend?
also, have you checked out AIOHA? you can do Hive authentication using keychain, hiveauth, hive signer, ledger and peak vault. all in one