HOW TO: Use Hive Keychain to Authenticate Users in An Application

in HiveDevslast year (edited)

If, like me, you've needed to know how to use Hive's awesome @keychain app to authenticate visitors to your website/dApp then you probably know that the method for doing so is hard to come by! Here's a guide that tells you all you need to know.

image.png

The developer guides for Hive, as with many open source projects, are out of date and incomplete. Sadly, one of the most important requirements for building an app on Hive is woefully under-described - user authentication.

At present (2022), the Hive Keychain system is the simplest and most efficient way to sign in to Hive websites, but it's documentation is (unironically) cryptic at times. The biggest challenge, though, is that the mechanism that apps rely on to use Hive to prove that a user owns a particular account is seemingly not documented at all! This information is fundamental to building apps on Hive, it needs to be visible all over - even included as initial information on Hive.io and other intro websites.

I had to spend several hours researching the process I will describe below and even then I only achieved the solution due to other developers pointing me in the right direction after appealing for help in several Discord servers.

Concept: How Does Authentication using Hive Keychain Work?


The design of Hive is such that every user has multiple encryption key pairs with different permissions attached to them - 'owner', 'active', 'posting' and 'memo'. Generally, for authentication in applications we are only interested in the posting and active keys, since these confer the necessary permissions used in most apps and are sufficiently important that most users won't give them away to other people (The active key is more powerful than the posting key, so consider checking that if you want to be sure that the person accessing your app is very likely to be the true owner of the Hive account in question).

Hive Keychain allows us to access the public key part of the private/public key pairs that are attached to all Hive accounts. So if someone attempts to sign in to our app using Hive Keychain, we can grab the public key and do some useful things with it.

Essentially, we create a unique message as text and use keychain to encrypt it into a garbled set of characters using one of the private keys associated to the user's Hive account. We then securely send this string of encrypted characters, along with the original (unencoded) message, plus the public key partner of the private key that was used to do the encryption to our server.

We then use the Hive API to check that we have the correct public key for the Hive account in question. Finally, we decrypt the encrypted message using the provided public key and check that the decrypted text matches the unencrypted text that our website originally created when the user attempted to sign in.

If the two text strings are equal then we know that whoever is attempting to sign in to your site does indeed have access to the real private key for the Hive account being used. This, then, allows us to treat this person as authenticated in our app.

Code: How To Authenticate Hive Accounts Using Hive Keychain


There are several steps to this process. We start out using Javascript in the browser to connect to the user's Keychain plugin.

Check that the Keychain plugin is installed


The following line checks to ensure that the keychain plugin is active:

if(window.hive_keychain)

Note: You need to interact with keychain via events in the browser since the timing of it's instantiation is such that it is not initialised when the DOM is ready in the browser (there is a short time delay).

Retrieve and check the Hive Username


Next, get the user's hive username somehow - typically you will add an HTML input element to your page and ask the user to type their username into it.

You should validate the username to at least ensure that it is present and not an empty string.

Create a unique message to encode


Use a timestamp for the present data/time and other information to create a string of text that can be encrypted and tested for the accuracy in our process of later decrypting it on the server.

A combination of the hive username, the current page address and a timestamp is sufficient.

Use 'requestSignBuffer' to encode the message


Keychain includes a function called requestSignBuffer which allows us to encode a message using either the private posting or private active key of a user. The following function call will trigger this process - you pass in the Hive username and also the message string to be encoded.

window.keychain.requestSignBuffer(hiveUsername, JSON.stringify(messageObj), 'Posting', signBufferOutput => {})

This function also requires a callback function (named 'serverResponse' in this example), which will run after the process completes.

Inside the callback we will send the relevant information to our server.

Send authentication data to our server


We need to use standard browser javascript to send the output from the requestSignBuffer function to our server.

var xhr = new XMLHttpRequest();
xhr.open('POST', '/yourLoginUrl', true);
xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
xhr.onload = function () 
{
   var serverResponse = JSON.parse(this.responseText);
   // do stuff in the webpage after server responds
};
xhr.send(JSON.stringify({ 'data': signBufferOutput }, null, 2));
}, null, 'Login to the app.');

Process the authentication data on the server


Now we need to do several things, firstly check to see if the user exists in our app's database or list of users. Either create a new user for them if they have not signed in before, or send them to a signup page if that's what you need.

Once we have related the user to a record in our database, we can check that the data that has been output by Hive Keychain does indeed confirm that the user is who they say they are.

The server will receive the following data from the browser:

Hive username (as text).
The unencoded message (as text).
The type of Hive key that is being used (as text).
The encoded message in a variable called 'result' (as text).
The relevant public key for the Hive account.

Check that these are present, validate as you prefer.

Confirm Public Key


You can use the dHive library to check the Hive blockchain to confirm that the provided public key does belong to the named Hive account by running:

await client.keys.getKeyReferences([publicKey]);

Which returns the name of the hive account to which the public key is associated. Note: the dHive documentation for this function seems to be out of date or at least incomplete. There is currently no mention of the correct syntax to use to call the 'accountByKeyAPI' class using dHive, but I managed to find it in some source code from another project on Github.

Now you have checked that the username you have been provided from the browser is the correct one for the public key that was provided.

Verify the message


Now we can finally check that the encrypted message that was sent from Hive Keychain (encrypted using one of the user's private keys) can be decoded using their public key and that it matches the original text that was encrypted by Keychain.

The following three commands from the dHive library will perform the check.

The first two instantiate the encoded message and the public key as appropriate objects from the dHive library. The third command performs the verification, whereby the encoded message is decoded using the supplied public key and is compared to the original, unencoded, text.

sig = dhive.Signature.fromString(encodedMsg);
key = dhive.PublicKey.fromString(publicKey);
result = key.verify(dhive.cryptoUtils.sha256(originalMsg), sig);

The resulting variable will be true if the verification succeed and false if not. If the result is true, then the server has successfully confirmed that whoever sent the data from a browser did indeed have the ability to encode text using the private key associated with the provided hive username. This means that we know they have access to the private keys and have therefore authenticated themselves - without needing to provide us with any private keys.

Conclusion


Hive Keychain and the private/public key encryption model built into Hive allow us a nice way to authenticate accounts without any risk on the part of the Hive account owner. Being able to do this using javascript makes it simple to manage Hive user authentication and to create interesting Decentralised apps on Hive.

Thanks to @stoodkev and the rest of the Keychain team, plus supporting community developers for making this all work!



Wishing you well,
Ura Soul



Read My User Guide for Hive Here


Hive Alive Banner 2.png
Powerful insights into the Hive blockchain are available at my website, Hive Alive.
Including the only way to track downvotes on Hive - The Untrending report


The NFT Symposium
The NFT Symposium is a community space where NFT creators, artists, traders, enthusiasts & visionaries rub virtual shoulders, share ideas, start projects, grow together & learn.

Get paid to mine your imagination for the benefit of the entire NFT world:

NFTSymposium.io.

Crucial Web, digital marketing agency in Norwich, UK
Looking for ethical Digital Marketing Agency?
@crucialweb can help you to grow and innovate online.

Sort:  

Thank you very much for this wonderful info..

You are welcome.

Thank you for this information. Btw some kind of GitHub example code would
be appreciated as much more useful than a long text description. :)

You are welcome. I aim to stay away from relying on corporate products where possible - Github is now a Microsoft product, whereas Hive is public.

Sure. Then maybe here in "'''" or whatever is markdown for code. Just having it in one file with comment ("//") in a "file" would make it much easier and faster to read for tech people. Still great source thanks again.

Ok yes, good idea, I just edited the post to include code markdown for readability.

Great! Thank you again:)

Is there any way I can interact with the HiveKeychain through Python API? :(

Keychain operates in browsers, which themselves run javascript - so you can't get around using Javascript in the browser.

I don't use Python myself but I imagine you would be able to run Python on your server to process the server side component of the process described here. There are tutorials for Python on the Hive developer website, but you might need to dig around to find the correct functions to use for the keychain authentication process.

The library 'Beem' is promoted for Python with Hive but I think that the author, @holger80, no longer maintains it. I can see a few functions in Beem that might do what you need, but I have no experience with it - I imagine if you ask in the Hive developer Discord area you will get the answers you need.

Oh yeah I am fully aware of Beem and Hive-engine libraries . In fact I had my own site up ad running but only part where I struggled was connecting to Keychain .

Thanks for the reply :)

I see, ok - well, the code for the verify function in dHive may exist in beem somewhere, but otherwise you can go and trace the verify code to it's parent project and then maybe recreate it in Python. Personally, I would ask other developers who use Python or maybe @holger80 which functions to use in Beem to do the verification.

this is a huge work, thanks so much for taking out such time to educate me as a person, learning so much already


The rewards earned on this comment will go directly to the people( @keychain ) sharing the post on Twitter as long as they are registered with @poshtoken. Sign up at https://hiveposh.com.