
Steem Keychain is a Steem wallet plugin for browsers that enables users to securely store your private keys and sign transactions using their key(s) securely.
At 2020 Steem Keychain should be the preferred way to log into any Steem dApps. In this post, I am going to write about how can we implement Steem Keychain authentication (also authorization) into our Node JS website or API.
Goal
Our goal is to verify a user is a user they are claimed to be. So, we are going to verify by having them sign a predefined message using any of their private keys ( Posting, Active, Memo) and later trying to decode the signed message using their public key (Posting, Active, Memo - whichever was used to sign). If we can recover the original message, this validates that the user has to access/owns the account. So, they are authenticated. Now we can issue them a token (JSON Web Tokens) signed by us to authorize the use of our website/API.
Client
We need a predefined message preferably unique for each user. We will ask our users to sign the message using their Posting key. After signing we are going to send a POST request with the username
, message
, and signed message
to our API login endpoint /users/login
. API.post
is an interface to send HTTP request using axios. If successful our server would respond with a JWT token which we can use to access/modify data.

Here is how the code might look like.
const message = Date.now(); // Generating the message
window.steem_keychain.requestSignBuffer('username', message, 'Posting', async (r) => {
if (r.success) {
// User has signed the message
try {
// We are sending HTTP POST request to our API login endpoint
// with the username, message, and the signed message
const { token } = await API.post('users/login', {
username,
message,
signed_message: r.result,
});
// Saving the token into localStorage for later use
localStorage.setItem('token', token);
// More codes to use the received token
} catch(e) {
console.log(e);
}
}
});
Server
We have seen how to ask users to sign and send the signed message to our login endpoint. Now let's see how the login endpoint might look like. I am going to assume we are using Express JS for our backend server.
First, we pick username
, message
, and signed message
from the POST request's body. Then we are going to fetch the users Publick posting key from the chain. After that, we are going to recover the public key from the signed message and match it against the public key pulled from the chain.
If both match, we can safely assume the user is who they are claimed to be. We are going to issue them a JTW token which they can use to interact with our website/API.
const jwt = require('jsonwebtoken');
const { Router } = require('express');
const { Client, Signature, cryptoUtils } = require('dsteem');
const steemClient = new Client('https://api.steemit.com');
const router = new Router();
router.post('users/login', async (req, res) => {
try {
// Picking username, message, and signed messsage
// from the request body
const { username, message, signed_message: signedMessage} = req.body;
// Fetching account info from the chain
const [account] = await steemClient.database.getAccounts([username]);
const pubPostingKey = account.posting.key_auths[0][0];
// Recovering public key from the signed message
const recoveredPubKey = Signature.fromString(signedMessage)
.recover(cryptoUtils.sha256(message));
if (pubPostingKey === recoveredPubKey.toString()) {
// Public key matched.
// We have verified the user has access to the account.
// let's issue them a JTW token
const token = jwt.sign({
sub: username,
// Any other data you may need
}, process.env.JWT_SECRET, { expiresIn: '12h'});
// Responding with the generated token
return res.json({ token });
}
} catch(e) {
console.log(e);
}
return res.json({ error: 'Invalid login details.' });
});
In the example above we are issuing only one token (access key), we can extend it to issue two or more tokens (refresh key) too. Also, make other endpoints to support full OAuth2 authentication flow. You can also extend it by generating the message on the server and saving them into the database along with the session to allow/control multiple sessions and enable users to end a session as we see on Facebook and Google.
Please let me know if you have any suggestions in the comments below.
I am not claiming this is the best way to authenticate users using Steem Keychain. Please use it at your own risk and test the codes in your projects. I can not be held responsible for any loss might happen as a result of using these codes.
