When I decided to integrate Steem Keychain with @steeveapp, it was not clear to me how to establish a user session with the server, how to log the user in. I spent some time researching and thinking, so I decided to write down how I did it in the end and share it with others.
Being a Detective
At the beginning, when I was implementing authentication with SteemConnect, the situation was pretty clear. You ask SteemConnect and you get a token that you can use to verify user's Steem identity. But there was nothing like that with Steem Keychain, no tokens, not to mention just a few exported methods existing at the time I started checking the extension.
Anyway, when skimming through the README on GitHub, I stumbled over the section called Decode Memo / Verify Key, which says that requestVerifyKey
can be used to log the user in. No other details there, so although I knew what I was supposed to use, I didn't know what to do exactly. How to verify user's identity on the server?
The Authentication Flow
The flow I came up with turned out to be somehow funny to me because it incorporates exchanging encrypted memos between the server and the web application as if they were having an encrypted Steem conversation with each other.
So, here is what I came up with, step by step:
- [APP] Ask the user to insert their Steem username.
- [APP] Post
username
to/login/steem_keychain
. - [SERVER] Encrypt
username
with a symetric-key algorithm (like AES) to getencrypted_username
. This requires a secret to be prepared in advance and stored on the server, which is not related to signing JWT tokens or the blockchain. - [SERVER] Fetch the given user's public memo key from the blockchain.
- [SERVER] Encrypt
encrypted_username
using the public memo key to getencrypted_memo
and return it in the response. - [APP] Ask Steem Keychain to decrypt
encrypted_memo
received using the stored private memo key. - [APP] Post the decrypted memo (
encrypted_username
) to/login/steem_keychain/callback
. - [SERVER] Decrypt
encrypted_username
using the stored private secret (AES) to getusername
. - [SERVER] Generate a JWT token for the given username. Return it in the response.
- [APP] Store the returned JWT token. The session is established.
As apparent, the whole flow works iff the user manages to decrypt the message using their private memo key, which is the step verifying Steem identify. The web application cannot mess up with what is received from the server since it is encrypted and the secret is kept on the server only.
The reason why it is not the JWT token itself returned as encrypted_memo
is that we need the web application to ping the server back, letting it know that the session is established in case there is any necessary logic to be executed.
So, what do you think? Can it be done in a different or simpler way?
EDIT: There is a simpler way when using requestSignBuffer
, which is an API call that was not available when I was implementing this for Steeve.
Steem Keychain for Angular
ngx-steem-keychain.When implementing this for @steeveapp, I decided to turn my efforts into a public Angular module that anybody can use to get up and running with Steem Keychain quickly. All hail
I am posting updates regularly using Utopian:
Congratulations @void! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :
Click here to view your Board of Honor
If you no longer want to receive notifications, reply to this comment with the word
STOP
Do not miss the last post from @steemitboard:
Congratulations @void! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :
Click here to view your Board of Honor
If you no longer want to receive notifications, reply to this comment with the word
STOP
Do not miss the last post from @steemitboard: