Work in Progress: A Simple Flask App for Hive Keychain Login
Hey everyone,
Today I wanted to share something I've been tinkering with – a very early, crude, and simple Flask application designed to handle a Hive Keychain login using a posting key signature. This is definitely a work in progress, but I thought I'd put it out there for anyone interested.
The project is called flask_keychain
and the idea is to provide a basic backend that can:
- Receive a login request from a frontend that uses Hive Keychain to sign a message.
- Verify the signature against the user's posting key.
- If valid, issue a simple session token.
How It Works (The Gist)
The system involves a simple HTML frontend that uses JavaScript to interact with the Hive Keychain browser extension, and a Python Flask backend to verify the signed message.
Frontend (JavaScript & Keychain):
- When you enter your username and click "Login," the JavaScript captures the username.
- It then calls
window.hive_keychain.requestSignBuffer()
. This prompts Hive Keychain to ask you to sign a message (in this basic example, it's the current UTC date/time string) using the posting key of the entered username. - If you approve in Keychain, the extension returns the signature (
response.result
) and the public posting key (response.publicKey
) that was used. - The JavaScript then sends your
username
, thesignature
(as "challenge"), thepublicKey
, and the originalmessage
(as "proof") to the Flask backend's/login
endpoint.
Here's the core JavaScript that handles the Keychain interaction and the call to the backend:
function getCurrentUTCDateTime() { const now = new Date(); return now.toISOString(); } document .getElementById("loginForm") .addEventListener("submit", function (e) { e.preventDefault(); const username = document.getElementById("username").value.trim(); const status = document.getElementById("status"); status.textContent = ""; if (!username) { status.textContent = "Please enter your Hive username."; return; } if (typeof window.hive_keychain === "undefined") { status.textContent = "Hive Keychain extension not detected!"; return; } const datetimeToSign = getCurrentUTCDateTime(); // This will be our message window.hive_keychain.requestSignBuffer( username, datetimeToSign, // Message to sign "Posting", // Key type function (response) { if (response.success) { status.textContent = "Posting signed! Sending to API..."; const signature = response.result; const pubkey = response.publicKey || (response.data && response.data.publicKey) || null; if (!pubkey) { status.textContent = "Could not retrieve public key from Keychain response."; return; } const payload = { challenge: signature, // The signature from Keychain username: username, pubkey: pubkey, // The public key Keychain used proof: datetimeToSign, // The original message that was signed }; fetch("/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }) .then((r) => r.json()) .then((data) => { if (data.success) { let msg = "Login successful! <br>"; if (data.token) { localStorage.setItem("token", data.token); msg += ` Token: <code>${data.token}</code> <br>`; } status.innerHTML = msg; } else { status.textContent = data.error || "Login failed."; } }) .catch((err) => { status.textContent = "API error: " + err; }); } else { status.textContent = "Keychain signature failed."; } }, ); });
Backend (Python Flask &
hive-nectar
):- The
/login
route in Flask receives theusername
,signature
(referred to as "challenge" from the frontend),publicKey
, and originalmessage
(referred to as "proof" from the frontend). - It fetches the actual posting keys for the provided
username
from the Hive blockchain usinghive-nectar
. - It verifies that the
publicKey
sent by the client is indeed one of the account's valid posting keys. - It then uses
nectar-graphenebase
's (a component ofhive-nectar
)verify_message
function to check if thesignature
is valid for the givenmessage
andpublicKey
. - If everything checks out, it generates a secure random session token (using
secrets.token_urlsafe
) and sends it back to the client.
Here’s the key Python snippet from
app.py
for the verification:# (Previous steps: get data from request, fetch account's posting keys) # 'message' is what Keychain signed (datetimeToSign from JS, sent as 'proof') # 'signature' is the hex string from Keychain (sent as 'challenge' from JS) # 'pubkey' is the public key Keychain reported using for signing # Check that provided pubkey is one of the account's actual posting keys if pubkey not in posting_keys: return jsonify({ "success": False, "error": "Provided public key is not a valid posting key for this account.", }), 400 # Verify signature try: recovered_pubkey_bytes = verify_message(message, bytes.fromhex(signature)) recovered_pubkey_str = str(PublicKey(recovered_pubkey_bytes.hex(), prefix="STM")) valid = recovered_pubkey_str == pubkey except Exception as e: return jsonify({"success": False, "error": f"Signature verification error: {str(e)}"}), 400 if not valid: return jsonify({"success": False, "error": "Signature is invalid."}), 401 # Success: generate and return a session token token = secrets.token_urlsafe(32) sessions[token] = username # Simple in-memory store for this example return jsonify({"success": True, "username": username, "token": token})
- The
This frontend/backend interaction provides a basic but functional way to authenticate a Hive user via their posting key.
The Basic Frontend
I've included a super simple HTML template (login.html
) that just provides a basic login button which uses the JavaScript above to trigger the Keychain signature request and send it to the Flask backend. If successful, it just displays the token.
Where to Find It
This is very much a proof-of-concept and a starting point. If you're interested in playing around with it or seeing the basic structure, you can find the code on GitHub:
https://github.com/TheCrazyGM/flask_keychain
It's not meant to be a production-ready solution as-is, but more of a demonstration of how one might start building a Flask backend for Hive Keychain posting key logins. Maybe it'll be useful to someone looking to integrate Hive login into their Python web projects!
EDIT: I would like to give a shoutout to @sagarkothari88 who made the distriator api login, which inspired this idea.
As always,
Michael Garcia a.k.a. TheCrazyGM
Doing the same thing for https://hiveearnings.botlord.eu/ using flask, signin via Hive Keychain. It’s not really needed yet (no info there yet that requires login), but wanted to give it a try as well, and will need it in the future.
!HOPE
!PIZZA
!INDEED
!ALIVE
!BBH
!STRIDE
!WEIRD
!DUO
!PIMP
You just got DUO from @borniet.
They have 1/1 DUO calls left.
Learn all about DUO here.
I have future use, which is why I looked into it, and while I was working on some tools making use of Distriator the other day, the api login / return token just kinda meshed with what I had in mind. And of course python is more my thing for the backend, so wanted to give it a shot using hive-nectar (which also added to my knowledge how the cryptography works in it, as it still needs some work there too.)
Tap into Distriator!
!PIMP
!PIZZA
Tell me more about Distriator!!! ;-) Sounds interesting!
BTW: I’ve recently switched the HiveEarnings tool too the Hive-Nectar lib as well! Still want to do a post about it too ;-)
!HOPE
!PIZZA
!INDEED
!ALIVE
!BBH
!STRIDE
!WEIRD
I'm glad someone is using it! Pypi tells me people are downloading it, but I don't hear many first hand accounts. So, please feel free to reach out to me of something isn't working right!
As far as what I was doing using the Distriator api, I'll have to ask my PM if he even wants me talking about that yet. 😅
Lol! I think I know your PM as well ;-)
Regarding Nectar: loving it, and so far no issues! Will let you know if that changes :-D Currently also using it in my next project! Would also love to recode the tipping bots to start using it as well. There's future in Nectar, there's none in Beem...
!HOPE
!PIZZA
!INDEED
!ALIVE
!BBH
!STRIDE
!WEIRD
$PIZZA slices delivered:
@borniet(4/15) tipped @thecrazygm (x2)
ecoinstant tipped thecrazygm
Come get MOONed!
Given that I don't (yet) know what a flask app is, I don't have much to say on this tool yet, other than it sounds like it would be very useful. 😁 🙏 💚 ✨ 🤙