Tutorial: Logging into a Web Application with Steem Keychain

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:

  1. [APP] Ask the user to insert their Steem username.
  2. [APP] Post username to /login/steem_keychain.
  3. [SERVER] Encrypt username with a symetric-key algorithm (like AES) to get encrypted_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.
  4. [SERVER] Fetch the given user's public memo key from the blockchain.
  5. [SERVER] Encrypt encrypted_username using the public memo key to get encrypted_memo and return it in the response.
  6. [APP] Ask Steem Keychain to decrypt encrypted_memo received using the stored private memo key.
  7. [APP] Post the decrypted memo (encrypted_username) to /login/steem_keychain/callback.
  8. [SERVER] Decrypt encrypted_username using the stored private secret (AES) to get username.
  9. [SERVER] Generate a JWT token for the given username. Return it in the response.
  10. [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

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 ngx-steem-keychain.

I am posting updates regularly using Utopian:


View this post on Steeve

H2
H3
H4
3 columns
2 columns
1 column
2 Comments
Ecency