Hive Authentication Services - Developer guide - Part 2

avatar
(Edited)

Today, we will see how a Private Key Storage Application (PKSA) can implement support for the HAS protocol.

This post is aimed at developers who would like to integrate the HAS protocol into existing Private Key Storage Applications or for those who want to develop their own PKSA.

As usual, I'll also try to be as educational as possible so that non-tech-savvy people can find information that they might be interested in as well.


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:


Integrating HAS into your Private Key Storage Application

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 denial 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 a PKSA needs to do is to open a WebSocket connection with a HAS server. Once connected, the HAS will send a connected message with 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 60 seconds.

2. Off-band Authentication Payload

When an APP wants to authenticate an account, it must provide the PKSA with off-band data (information NOT transmitted over the Internet) that we will refer to as auth_req_payload.

It can be provided to the PKSA through a QR code that is displayed by the app and manually scanned by the user, or by using a deep-link when on mobile.

The auth_req_payload has the following structure:

{
    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")

With this information, the PKSA knows which host to connect to and which account it should register (see below). It also knows it should receive an authentication request with a specific request identifier (uuid). Finally, it now owns a session encryption key that will be used to secure the authentication process and communication.

3. Account registration

Before being able to receive and process any request for an account from the HAS, the PKSA must prove to the HAS that it stores the user's private keys.

Once an account has been registered by a PKSA, the HAS will know it can safely send transactions requests from that account to the PKSA.

A PKSA should wait to get an off-band auth_req_payload before registering an account it manages, mainly because it may not know which HAS server it needs to connect to.

3.1 Retrieving the server public key

This step is implemented to secure the communication between the PKSA and the HAS and provide a way to later authenticate an account with certainty.

The PKSA asks the HAS for its public encryption key by sending the following message:

{ cmd: "key_req" }

The HAS responds with the following message:

{ 
    cmd: "key_ack", 
    key: string
}
  • key: The server public key to use to perform asymmetric encryption (something like "STM....")

3.3 Registering account(s)

The PKSA can register one or more accounts and do it either by issuing one command with multiple accounts or by issuing one command per account.

The PKSA sends the following message to the HAS:

{
    cmd: "register_req",
    app: string,
    accounts: [ 
        {
            name: string
            key_type: string,
            challenge: string   // "{{encrypted_time}}"
        }
        {{,...}}
    ]
}
  • app: can contain any value identifying the PKSA
  • accounts: an array that can contain one or more account objects
    • name: the Hive account name
    • key_type: the key type used to encrypt the challenge. It can be one of posting|active|memo
    • challenge: the UNIX time encrypted using both the account private key and the HAS server public key

The challenge sent to the HAS for each account allows the HAS to be sure that the PKSA has access to the private keys of the account it wants to register.

This prevents malicious actors from creating a PKSA, registering accounts for which they do not have private keys, and sniffing requests that would be relayed to them by the HAS.

Each account challenge is built by encrypting the actual UNIX time with both the account's private key and the server's public key. The PKSA can use any account key that it stores (posting, active or memo) to encrypt the challenge.

The HAS will then:

  • decode the challenge using its own private key
  • ensure the message has been encrypted by the account by matching the public key retrieved from the encrypted challenge with the account public key retrieved from the blockchain.
  • check that the provided UNIX time is within a 3 seconds boundary from its actual time. This check is performed to avoid malicious actors to reuse challenges they could have got their hands on.

The register_req command can be issued multiple times.
If an account is already registered, the command will be ignored.
If the register_req command involves multiple accounts, the registration process will stop on the first failure if any, meaning some accounts may not be registered.

For each successfully registered account, the HAS server will reply with the following message:

{
    cmd: "register_ack",
    account: string
}
  • account: the account that has been successfully registered

Timing

The PKSA registration can be performed before or after the APP will issue authentication or transaction requests.

a) If the PKSA registration occurred before the requests are issued, it will receive those requests immediately.

b) If no PKSA is registered when the HAS receives authentication or transaction requests, it will queue them, waiting for a PKSA to register. If no PKSA registers before they expire, requests are discarded.

In both cases, (a) and (b), the APP will be notified of the requests' pending or expired status.

4. Authentication

To process the authentication request and secure the communication between the application and the PKSA, they need to share some out-of-band information. This out-of-band information will allow the APP and PKSA to communicate with each other securely.

4.1 Authentication payload

After reading the auth_req_payload and registering the account with the HAS, the PKSA will receive the following authentication request message:

{
    cmd: "auth_req", 
    account: string,
    data: string,
    uuid: string, 
    expire: number
}

  • account: the Hive account name that the application wants to authenticate
  • data: the Base64 representation of an encrypted auth_req_data object
  • uuid: the request identifier
  • expire: UNIX timestamp when the request will expire

The structure of the auth_req_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 PKDA must decrypt the auth_req_data object using the encryption key previously shared with the PKSA (auth_key). By encrypting the auth_req_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.

The PKSA should verify that the uuid found in the auth_req message matches the on from the auth_req_payload and ignore any message with a mismatching uuid

A PKSA which doesn't manage an account:

  • will not be able to register that account to the HAS and therefore will not receive the related auth_req requests
  • should ignore and not reply to an auth_req request it can't process with an 'auth_err' (edge case where it registered the account but removed it from its managed accounts before getting the auth_req message)

4.2 Feedback to user

Once the PKSA receives the authentication request from the HAS, it should display it to the user and ask for approval or denial.

4.3 Authentication Approval

If the user approves the authentication request, the PKSA must:

  • create a new token with an expire value or reuse an existing one.
  • store the token, expire and key values locally.
  • create an "authentication approval data" object (auth_ack_data) that it will send to the APP

The structure of the auth_ack_data is:

{
    token: string,
    expire: number,
    challenge: string = undefined
}
  • token: session token (we recommend using a UUID)
  • expire: UNIX timestamp when the token will expire
  • challenge: optional if the APP provided a public key to the PKSA, it must contain the account name encrypted with the account private posting key.

The PKSA must then encrypt the auth_ack_data object using the encryption key previously shared with the APP (auth_key).

Finally, the PKSA then inform the HAS of the user's approval by sending the following message:

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

The encryption of auth_ack_data is performed to ensure that a malicious actor operating a HAS cannot bypass the PKSA to approve an authentication request.

It will also make the HAS unaware of what's going on between the app and the PKSA and unable to tamper with the authentication request process.

Being the only one being able to decrypt the auth_ack.challenge using its encryption key, the APP has 100% certainty that the encryption process was made by a PKSA which got the encryption key from reading the off-band auth_req_payload.

4.4 Authentication Refusal

If the user rejects the authentication request, the PKSA can inform the HAS with the following message:

{
    cmd: "auth_nack",
    uuid: string,
    challenge:string
}
  • uuid: the request identifier
  • challenge: uuid encrypted with the APP encryption key from auth_payload and converted to Base64

See Authentication Approval above for more information about the challenge

4.5 Errors

If for any reason the PKSA fails to process the authentication request, it can inform the HAS with the following message.

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

5. Transactions

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

The APP can 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.

5.1 Transaction request

When an APP sends a transaction request involving an account to the HAS, if the PKSA has registered the account to the HAS then it will receive the following message:

{
    cmd: "sign_req", 
    account: string,
    token: string,
    data: string,
    uuid: string,
    expire: number
}
  • account: the Hive account name
  • token: the authentication token
  • data: the Base64 representation of an encrypted sign_data object
  • uuid {string} the transaction request identifier
  • expire {Number} UNIX timestamp when the request will expire

The structure of the sign_data object 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.

Before sending its sign_req request, the APP has encrypted the sign_data using the encryption key shared with the PKSA during the authentication process.

Only a PKSA having previously authenticated an account and having access to the encryption key will be able to decrypt the operations to be put in a transaction and to be signed.

Therefore, the HAS is completely unaware of what's going on between the APP and the PKSA.

5.2 Feedback to the user

Once the PKSA receives a transaction request from the HAS, it should display it to the user and ask for approval or denial.

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

5.3 Transaction approval

If the user approves the transaction request, the PKSA must check if the App requested it to broadcast the transaction to the blockchain.

If so, it must try to do it and inform the HAS upon success or failure.
If not, the PKSA must inform the HAS of the user's approval and return the signed transaction.

The PKSA sends the following message:

{
    cmd: "sign_ack",
    uuid: string,
    broadcast: boolean,
    data : object
}
  • uuid: the transaction request identifier
  • broadcast: true if the transaction was broadcasted by the PKSA, otherwise false
  • data: the transactions id (txid) if broadcast is true or the signed transaction signed_tx if broadcast is false.

5.4 Transaction refusal

If the user doesn't approve the transaction request, the PKSA can inform the HAS with the following message:

{
    cmd: "sign_nack",
    uuid: string,
    challenge:string
}
  • uuid: the request identifier
  • challenge: uuid encrypted with the APP encryption key from auth_payload and converted to Base64

5.5 Errors

If for any reason the PKSA fails to process the transaction request, it can inform the HAS with the following message.

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

Wrap up

We now have a detailed description of how a Private Key Storage Application can interact with the Hive Authentication Services.

The Keychain team recently announced that they are working on integrating HAS support into their Keychain Mobile app. Although the development is progressing well, the integration is not yet complete.

How then if you want to test the integration of the HAS protocol in your application? One solution would be to run your own PKSA.

That's what we will see in my next post. I will show you how to put into practice what has been described here to create and run a PKSA.

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
23 comments
avatar

Reblogged, twittered and upvoted and spreading. As I feel that we can all benefit from this.

0
0
0.000
avatar


🎯🎯🚀🎯🎯

Your post is interesting, we have selected it to be presented to
INTERCOMMUNITY - HIVE - AFFILIATE team.

Your post will be reblogged on @Target-Post, in order to increase its notoriety and be boosted (visibility, reading, comments and rewards).


Our affiliate earn passive income by delegating to @hive-affiliate. + 75 % of the curation rewards are shared with the affiliate delegators.

If you are active we boost your rewards from + 50% to + 75% to + 100%



🚩 Read Our Guidelines to get more information

🎯🎯🚀🎯🎯


0
0
0.000
avatar

Congratulations @arcange! Your post has been a top performer on the Hive blockchain and you have been rewarded with the following badge:

Post with the highest payout of the week.

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

Check out the last post from @hivebuzz:

Hive Power Up Day - November 1st 2021 - Hive Power Delegation
Bee ready for the 2nd Hive Power Up Month challenge!
0
0
0.000