Hive Authentication Services - Developer guide - part 1

avatar
(Edited)

A few days ago, I introduced the Hive Authentication Services and its protocol description.

So far, I have approached the details of these new services in a fairly comprehensive manner in order to give you an overview of the possibilities that will be offered to you.

I now suggest you dive deeper with a more technical description aimed at developers who would like to integrate the HAS protocol into their applications.

As usual, I will also try to be as educational as possible so that the layman can also find information that may be of interest to him.


If you haven't already done so, support the project and vote for its proposal on Peakd, Ecency, hive.blog or using HiveSigner

I also invite you to read:


HAS Integration

The Hive Authentication Services (HAS) rely on the WebSocket protocol to exchange data between Applications (APP) and the Private Keys Storage Application (PKSA) via persistent connections. The data can be passed in both directions as “payloads”, without breaking the connection and additional HTTP requests.

The APP opens a WebSocket connection to the HAS endpoint and sends authentication and transactions requests to it.

The PKSA opens a WebSocket connection to the HAS endpoint, requests an encryption key from the server, registers the account(s) for which he will process requests, and wait for incoming authentication and transactions requests.

The HAS will queue requests from the APP and forward them to any newly or already connected PKSA. it will also relay back approval or refusal of the requests.

The dialogue between the different parties is done by means of JSON structured messages, each containing a cmd field that defines the nature of the message.

1. Connection

The first thing an APP needs to do is to open a WebSocket connection with a HAS server. Once connected, the HAS will send a connected message with the additional information.

{ 
    cmd: "connected", 
    server: string,
    socketid: string,
    timeout: number
}
  • server: hostname you are connected to (ex: "has-server.domain.com")
  • socketid: WebSocket connection identifier
  • timeout: time in seconds before the server considers requests to be expired. Default is 120 seconds (2 minutes)

2. Authentication

When a user starts an APP, the first thing the APP needs to do is authenticate the user, especially if the APP wants to interact later with the Hive blockchain.

Usually, this is done by entering a username and password and matching it against similar data stored somewhere.

Hive Authentications Services enables applications to authenticate their users by simply providing a username and relieving the applications from storing additional credentials data.

The credentials are stored in the PKSA local storage and act as a Two-Factor Authentication (2FA) provider.

The users only need to trust one PKSA, where they safely store their private keys. They no more will be required to provide any key to any HAS enabled application. Likewise, they are guaranteed that their keys will never leave the PKSA.

After the user has provided the APP with their account name, the APP will perform the authentication process.

2.1 Authentication request

Before sending its request, the APP must create an "authentication request data" object (auth_data) it will send to the PKSA

The structure of the auth_data is:

{
    token: string = undefined,
    app: {
        name: string,
        description: string = undefined,
        icon: string = undefined
        pubkey: string = undefined,
    }
}
  • token: optional a valid session token previously received from the PKSA
  • app: an object describing the application
    • name: short name of the app (ex: "peakd")
    • description: optional description of the app (ex: "Peakd for Hive")
    • icon: optional URL to retrieve the application icon (ex: "https://peakd.com/logo.png")
    • pubkey: optional a public key that the PKSA can use to return the account name encrypted with the account private posting key (challengeAccount). The encrypted data returned can be used by the app or its backend, if any, to validate the account against its public posting key.

The APP must then encrypt the auth_data object using the encryption key previously shared with the PKSA (auth_key). By encrypting the auth_data object, the HAS will be unaware of what's going on between the app and the PKSA and unable to tamper with the authentication request process.

Finally, the APP sends its request to the HAS using the following message:

{ 
    cmd: "auth_req", 
    account: string,
    data: string
}
  • account: the Hive account name that the application wants to authenticate
  • data: the Base64 representation of an encrypted auth_data object

The HAS will reply with an auth_wait message:

{
    cmd: "auth_wait",
    uuid: string,
    expire: number,
    account: string
}
  • uuid: a unique identifier given by the HAS to the request
  • expire: UNIX timestamp when the authentication request will expire
  • account: account doing the authentication request

2.2 Off-line Authentication Key

Once the APP receives the request confirmation (auth_wait and uuid), it should tell the user to start its PKSA to approve or reject the authentication request before the request expires.

The application must provide the user with out-of-band data. These data will be read by the PKSA in order to know which HAS server to connect to and to privately share an authentication key (auth_key) used to encrypt payloads.

This can be done by providing the user with a deep link or QR code representation of that deep link.

To create the deep link:

  1. create an auth_payload object:
{
    account: string
    uuid: string,
    key: string,
    host: string
}
  • account: the username of the account performing the authentication
  • uuid: the request identifier received with the auth_wait reply.
  • key: an app-generated encryption key (we recommend using a uuid)
  • host: URL of the HAS server to connect to (ex: "wss://has-server.domain.com")
  1. convert the auth_payload object to a base64 string (auth_payload_base64)

The URI for the deep link will be:
has://auth_req/{{auth_payload_base64}}

Example:

The following auth_payload

{
    "account":"arcange",
    "uuid":"9b0e2dc3-f574-4766-abdd-c429dce11284",
    "key":"03f63469-5a35-47cb-a6b4-e8c4d3144cf9",
    "host":"wss://has-server.domain.com"
}

will generate the following URI:

has://auth_req/eyJhY2NvdW50IjoiYXJjYW5nZSIsInV1aWQiOiI2NThmYzczYi1jN2MyLTQ3ODQtYWE2ZC04Mjk0MGUwNzg2OTgiLCJrZXkiOiJkOWY2OTY4NS1jMTYxLTQ2MWMtYmNkYS0wMzY4NTE3YjQzNmMiLCJob3N0Ijoid3NzOi8vaGl2ZS1hdXRoLmFyY2FuZ2UuZXUifQ

and will produce the following QR code

2.3 Authentication approval

If the user approves the authentication request with its PKSA, the latest will send an auth_ack message to the HAS with an access token and its expiration.

When the HAS will receive the user approval from its PKSA, it will forward it to the APP which will receive the following message:

{
    cmd: "auth_ack",
    uuid: string,
    data: string
}
  • uuid: the request identifier
  • data: auth_req_data encrypted with the auth_key and converted to Base64

The APP must validate the received uuid against the request ID (uuid) that it received from the HAS in the auth_wait message and ignore the auth_ack message if they don't match.

The APP must decrypt the auth_ack_data object using the encryption key previously shared with the PKSA (auth_key). If the APP cannot decrypt and parse auth_ack_data, the APP must ignore the auth_ack message.

This auth_ack_data encryption/decryption process has been put in place to ensure that a malicious actor operating a HAS cannot bypass the PKSA to approve an authentication request.

As the encryption key has been provided off-line to the PKSA, the HAS has no access to it and is therefore unable to decrypt, tamper then (re-)encrypt any data exchanged between the APP and the PKSA.

The structure of the auth_ack_data is:

{
    token: string,
    expire: number,
    challenge: string = undefined
}
  • token: session token
  • expire: UNIX timestamp when the token will expire
  • challenge: optional if the APP provided a public key to the PKSA, it contains the account name encrypted with the account private posting key.

The application should store the token safely. This token will be used with each subsequent request. It also prevents the need for the user to re-authenticate while their token is not expired.

It is up to the APP to reuse the token for as long as it is valid or to shorten its life by reinitiating a new authentication process without providing the existing token back to the PKSA.

When the token expires, any transactions request will be rejected with an unauthorized error message sent to the application (see below)

2.4 Authentication refusal

If the user doesn't approve the authentication request, the PKSA will send a refusal message to the HAS. The HAS will then forward the following message to the APP:

{
    cmd: "auth_nack",
    uuid: string,
    challenge: string
}
  • uuid: the request identifier
  • challenge: the uuid encrypted with the authentication key provided off-line (see auth_key above)

2.5 Errors

If for any reason the PKSA fails to process the authentication request, it can send an error message to the HAS that will forward it to the APP. The same applies if the error is generated by the HAS.

In both cases, the APP will receive the following message:

{
    cmd: "auth_err",
    uuid: string,
    error: string
}
  • uuid: the request identifier
  • error: an error message

2.6 Expiration

It may come that the APP never receives any reply to its request from the HAS.

There can be many reasons for this, like users not starting their PKSA or not approving or denying authentication requests they receive.

The APP should monitor requests' expiration against the expire timeout provided in the auth_wait message. They should abort the authentication process and discard pending requests as well as any related reply they may receive.

3. Transactions

Once the user is authenticated, they can start to transact with the Hive blockchain through the APP.

The APP can now either request the PKSA to only sign transactions (in order to broadcast the transactions by itself to the blockchain) or ask the PKSA to sign and directly broadcast the signed transaction to the blockchain.

3.1 Transaction request

The APP can request the PKSA to sign and/or broadcast a transaction.

Before sending its request, the APP must create a "sign request data" object (sign_data) it will send to the PKSA

The structure of the sign_data is:

{
    key_type: string,
    ops: string,
    broadcast: boolean
}
  • key_type: the key type required to sign the transactions. It can be one of posting|active|memo.
  • ops: an array of operations
  • broadcast: true if the PKSA must broadcast the transaction to the blockchain. false if the PKSA must return a signed transaction but not broadcast it to the blockchain.

The APP must then encrypt the sign_data object using the encryption key previously shared with the PKSA (auth_key). By encrypting the sign_data object, the HAS will be unaware of what's going on between the app and the PKSA and unable to tamper with the sign request process.

Finally, the APP sends its request to the HAS using the following message:

{ 
    cmd: "sign_req", 
    account: string,
    token: string,
    data: string
}
  • account: the Hive account name
  • token: the authentication token
  • data: the Base64 representation of an encrypted sign_data object

The HAS will reply with a sign_wait message:

{
    cmd: "sign_wait",
    uuid: string,
    expire: number
}
  • uuid: a unique identifier given by the HAS to the request
  • expire: UNIX timestamp when the request will expire

3.2 Feedback to user

Once the APP receives the request confirmation (sign_wait + uuid), it should tell the user to start its PKSA to approve the transaction request before the request expires.

Note: It is strongly suggested to the APP and the PKSA to display part or all of the uuid of the request to the user. This will allow them to match it on both sides and be sure to approve the right transaction

3.3 Transaction approval

If the user approves the transaction request with its PKSA, the latest will send a sign_ack message to the HAS. The HAS will then forward the following message to the APP:

{
    cmd: "sign_ack",
    uuid: string,
    broadcast: boolean,
    data: object
}
  • uuid: the transaction request identifier
  • broadcast: true if the transaction was broadcasted to the blockchain by the PKSA, otherwise false
  • data: contains either the transaction id (txid) if the transaction has been broadcasted or the signed transactions (signed_tx) if it has not been broadcasted.

3.4 Transaction refusal

If the user doesn't approve the transaction request, the PKSA will send a refusal message to the HAS. The HAS will then forward the following message to the APP:

{
    cmd: "sign_nack",
    uuid: string
}
  • uuid: the transaction request identifier

3.5 Errors

If for any reason the PKSA fails to process the transaction request, it can send an error message to the HAS that will forward it to the APP. The same applies if the error is generated by the HAS.

In both cases, the APP will receive the following message:

{
    cmd: "sign_err",
    uuid: string,
    error: string
}
  • uuid: the transaction request identifier
  • error: an error message

3.6 Expiration

It may come that the App never any reply to its request from the HAS.

There can be many reasons for this like users not starting their PKSA or not approving or refusing transaction requests they receive.

The APP should monitor requests' expiration against the expire timeout provided in the sign_wait message. They should abort the authentication process and discard pending requests as well as any related reply they may receive.

4. Code example

Here is a simple example of how an HTML web page can interact with the HAS infrastructure.

<script>
// Encryption key - should be generated dynamicaly
let auth_key = "c5376856-97d6-4951-9752-1c5ad82569fb"
// **HAS** variables
let username
let token
let expire
// Initialize WebSocket
if ("WebSocket" in window) {
    // The browser support Websocket
    ws = new WebSocket("wss://has-server.domain.com")
    // When the WebSocket is connected
    ws.onopen = function() {
        console.log("WebSocket connected")
    }
    // When the WebSocket receive messages
    ws.onmessage = function (evt) { 
        const message = JSON.parse(event.data)
        if(message.cmd) {
            // Process HAS protocol
            switch(message.cmd) {
                case "auth_wait":
                    // Application is waiting for auth approval
                    const json = JSON.stringify({
                        account: message.account, 
                        uuid: message.uuid,
                        key: auth_key,
                        host: "wss://has-server.domain.com"
                    })
                    const URI = `has://auth_req/${Buffer.from(json).toString('base64')}`
                    // Display the off-line info
                    alert("Start your **PKSA** favorite app - " + URI)
                    break
                case "auth_ack":
                    // User has approved account auth
                    token = message.token
                    expire = message.expire
                    Alert("Successfully authenticated")
                    break
                case "auth_nack":
                    alert(`authentication request ${message.uuid} denied`)
                    break
                case "auth_err":
                    alert(`authentication request ${message.uuid} failed: ${message.error}`)
                    break
                case "sign_wait":
                    alert(`transaction request ${message.uuid} is waiting for approval`)
                    break
                case "sign_ack":
                    alert(`transaction request ${message.uuid} approved`)
                    break
                case "sign_nack":
                    alert(`transaction request ${message.uuid} denied`)
                    break
                case "sign_err":
                    alert(`transaction request ${message.uuid} failed: ${message.error}`)
                    break
            }
        }
    }
    // When WebSocket is closed.
    ws.onclose = function() { 
        alert("WebSocket closed. Please reload the page...")
    }
} else {
    alert("The browser doesn't support WebSocket")
}

// Example of events generated by the application
function click_auth() {
    username = $("#username").val();
    const payload = { cmd:"auth_req", account:username, app: {name:"has-demo-client-html"} }
    ws.send(JSON.stringify(payload))
}

function click_sign() {
    // Broadcasting a custom_json to the blockchain
    const op = [ 
        "custom_json",
        {
            id: "test",
            json: '{"action":"test HAS broadcasting"}',
            required_auths: [],
            required_posting_auths: [username],
        }
    ]
    // Prepare the data to send
    const data = {
    key_type:"posting",
        [op]
    }
    // Encrypt the data with the key we provided to the **PKSA**
    const edata = CryptoJS.AES.encrypt(JSON.stringify(data),auth_key).toString()
    // Send the request to the **HAS**
    const payload = { cmd:"sign_req", account:username, data:edata, token:token, broascast:true }
    ws.send(JSON.stringify(payload))
}
</script>

Wrap up

In this (long) post, I have described all the steps to integrate the HAS protocol into your application and how easy it is to interact with the HAS.

In the next post, I will explain what is happening on the PKSA side and how you can run your own Private Key Storage Application.

Thanks for reading.


Support the HAS project!
Vote for the proposal on PeakD
Vote for the proposal on Ecency
vote for the proposal on Hive.blog
Vote for the proposal using HiveSigner

Vote for me as a witness



0
0
0.000
31 comments
avatar

pixresteemer_incognito_angel_mini.png
Bang, I did it again... I just rehived your post!
Week 78 of my contest just started...you can now check the winners of the previous week!
!BEER
9

0
0
0.000
avatar

I am not a programmer. I have no clue about coding.

But I like to comment to show my support and respect for your work! My deepest respect goes to people who can program and implement something like this.

!PIZZA

P.S. I already voted for the proposal.

0
0
0.000
avatar
(Edited)

PIZZA! PIZZA! PIZZA!

PIZZA Holders sent $PIZZA tips in this post's comments:
sgt-dan tipped arcange (x1)
@sgt-dan(1/10) tipped @beerlover (x1)
chrislybear tipped arcange (x1)

Learn more at https://hive.pizza.

0
0
0.000
avatar

This is a very useful reference post. Ill come back to this when i am implementing it in an app i have been thinking about resurrecting from the Steem days.
One thing that always concerned me by being an app developer was having to be responsible for peoples private keys in some way. I'll take this for a test drive and see how it works.

0
0
0.000
avatar

Great to read you are interested to support HAS in your apps.
Feel free to contact me if you have any questions or need help.

0
0
0.000
avatar

What's the advantage of signing in with Hive Authentication Services instead of signing in with Keychain? Keychain also does the signing locally without sharing the keys to anyone. Would it be possible to collaborate with Keychain instead of building another login service?

0
0
0.000
avatar

The browser extension you are probably referring to in your comment does not work on mobile.

I am actively working with the Keychain team to support the HAS protocol in Keychain Mobile.
It will allow users to store their keys in one place (Keychain Mobile) and authenticate within any application that supports the HAS protocol, either a mobile, desktop, or website app, without installing anything else.

0
0
0.000
avatar

Congratulations @arcange! You have completed the following achievement on the Hive blockchain and have been rewarded with new badge(s) :

You distributed more than 570000 upvotes.
Your next target is to reach 580000 upvotes.

You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word STOP

To support your work, I also upvoted your post!

Check out the last post from @hivebuzz:

Bee ready for the 2nd Hive Power Up Month challenge!
Trick or Treat - Share your scariest story and get your Halloween badge
0
0
0.000
avatar

This post has been manually curated by @steemflow from Indiaunited community. Join us on our Discord Server.

Do you know that you can earn a passive income by delegating to @indiaunited. We share 80 % of the curation rewards with the delegators.

Here are some handy links for delegations: 100HP, 250HP, 500HP, 1000HP.

Read our latest announcement post to get more information.

image.png

Please contribute to the community by upvoting this comment and posts made by @indiaunited.

0
0
0.000
avatar

I am not a programmer but has a few knowledge about it since we were taught some basics in college and I have a huge dream of becoming a programmer myself. But I should be totally honest, I still have to study this. I just can’t wait to comment to show support so here I am sending you virtual handshake 🤝. I voted for your proposal and recommended it to my friends. I also voted for you as witness. Congrats and best of luck.

0
0
0.000
avatar

I have a huge dream of becoming a programmer myself.

That's the way to go, leads to empowerment and freedom.
Thank you for your support and your virtual handshake @nikkabomb.
Here is a virtual hug and some !LUV 🤗

0
0
0.000
avatar

Hi again! I observe the HAS topic presented by You, and with each new post, I understand more and more, but still have a hole in knowledge. Could You share some online publications about out-of-band data ? Maybe it will be good to add some references about security topics mentioned here, to make the post more reliable.
Also, I have a question about malicious applications which sends requests for approval on behalf of other application, how does the HAS protocol prevent such an attack ?

0
0
0.000
avatar

Could You share some online publications about out-of-band data ?

Yes, more posts about it and how security is managed are coming... 😅

how does the HAS protocol prevent such an attack ?

That will be addressed in the coming posts too.
TLDR; auth_req sent by a malicious app to HAS will expire and be ignored if the user's PKSA is not running. If the PKSA is running, PKSA should ignore them if they did not retrieve a matching off-band auth_req_payload before.

0
0
0.000
avatar

I have loved this work you are doing and I think it is very cool. Although I am still learning about these systems, I liked the way you explain the whole process of operation of HAS. Really, this service is very useful. You have my support. Regards.

0
0
0.000
avatar

One for all security on mobile interesting and necessary!

Full backing, although I never venture onto mobile and rely purely on PC, call me old fashioned 😌

Have a great day and thanks for what you do into blockchain security for community.

!LUV

0
0
0.000
avatar

Thank you @joanstewart
I can be old-fashioned too but from time to time I jump into the present and use my mobile. 😆

0
0
0.000
avatar

Oh a few Apps never, banking or content creation would be dangerous with predictive text and fat finger syndrome.

0
0
0.000
avatar

Too late to vote another wonderful project that you have put together. Instead I will send you some !PIZZA token and a tip! Merci mon ami! A bientot sur le HIVEFEST!

0
0
0.000
avatar

It's never too late to support. Every vote matter, especially for a proposal with a one year time-frame.

I have been happy to meet you again at HiveFest. 👍

!BEER

0
0
0.000
avatar

It was good to see you again at HIVEFEST mon ami.

0
0
0.000
avatar

I was so excited to see this and hear your presentation at HiveFest. Are there plans for a Wordpress plug-in for us non devs? That would be a game changer for Wordpress users.

0
0
0.000
avatar

Thank you.

Are there plans for a Wordpress plug-in for us non devs?

Not that I know. But if you know people who have the skills to do it, don't hesitate to tell them about it. I will be happy to support it.

0
0
0.000