Create Publication

We are looking for publications that demonstrate building dApps or smart contracts!
See the full list of Gitcoin bounties that are eligible for rewards.

Tutorial Thumbnail
Beginner · 30 minutes

Using Azure Key Vault for Wallet Transactions using JavaScript

The most important piece of information for every Algorand wallet owner, is the private key. It is the most important because loss of that private key will result in the owner not being able to access the tokens associated to that wallet, without any possibility of recovery.

With Azure Key Vault one can store, retrieve and recover an account using your private key using the cloud, so you won’t loose it. In addition, iOS/Android wallets will be empty if you get a new phone when you transfer everything from the old phone to a new one. You will need your passphrase there too, for account restoration on the new phone wallet. And this can be easily retrieved from the Azure Key Vault.

This tutorial will provide the necessary information needed to sign Algorand transactions with a private key stored in Azure Key Vault.

RESOURCES

Requirements

Background

Azure Key Vault is a cloud service that provides a secure store for secrets. You can securely store keys, passwords, certificates, and other secrets. Azure key vaults may be created and managed through the Azure portal. In this tutorial, you create a key vault, then use it to store a secret and retrieve the secret to sign transactions on Algorand.

Azure Key Vault, and its Hardware Security Modules (HSM) offering, allows management and usage of cryptographic key pairs, without the private key ever leaving the vault, unless it’s for backup and restore operations, meaning, the risk of loss or exposure of the private key is reduced.

This tutorial will cover setting up of Azure account, creating Key Vault, Creating Payment Transaction, signing the transaction with secret key retrieved from Azure Key Vault and also recovering of private key.

Steps

1. Package Installation and Environment Setup

To get started create a local folder on your machine for the code, cd (change directory) into that folder
do npm init and install the following packages

npm install algosdk
This will install the Algorand JavaScript SDK. The algosdk ensures interactions with the Algorand blockchain.
EditorImages/2022/03/25 04:39/Screenshot_2022-03-19_at_03.19.54.png
Fig 1-1 Install algosdk

npm install --save @azure/identity
This will install the Azure Identity library. The Azure Identity library provides Azure Active Directory (Azure AD) token authentication through a set of convenient TokenCredential implementations.

npm install @azure/keyvault-secrets
Use the KeyVault Secrets client library to get access to Azure Key Vault.

EditorImages/2022/03/25 04:44/Screenshot_2022-03-19_at_02.44.49.png
Fig 1-2 Install Azure Identity and KeyVault Secrets

npm install dotenv --save
Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env. Storing configuration in the environment separate from code. You will create a .env file at the root of your project.

EditorImages/2022/03/25 04:37/Screenshot_2022-03-23_at_21.49.37.png
Fig 1-3 Install dotenv

On mac do `brew update && brew install azure-cli
This will enable interactions with azure portal from the command line. If you encounter any error while running the above command you can try to install from source with:
brew install --build-from-source [email protected].
If you are having problem installing the CLI this installation guide should be helpful.
EditorImages/2022/03/26 03:47/Screenshot_2022-03-19_at_03.01.05.png
Fig 1-4 Install azure-cli

File Structure

Note

Your file structure should look like this. Your .env and node module should be added to .gitignore file so you don’t end up exposing your credentials when you push to github.

EditorImages/2022/03/31 04:24/Screenshot_2022-03-31_at_05.23.22.png
Fig 1-5 File Structure

2. Azure Account Setup

Create a free Azure account and login to the portal. Create account here. There are two types of account the free account and PayAsYouGo account. The free account gives you access to the Azure portal to access the Azure features for a trial period of 30 days.

Create Azure Account

EditorImages/2022/03/25 04:51/Screenshot_2022-03-25_at_05.49.52.png
Fig 2-1 Create Account

Login to Azure Portal

After successful account creation you can then login.
EditorImages/2022/03/25 04:57/Screenshot_2022-03-25_at_05.49.23.png
Fig 2-2 Login

3. Create Resource Group

A resource group is a container that holds related resources for an Azure solution.To create resource
click on Resource Groups on the left pane to bring up Resource groups.
EditorImages/2022/03/31 03:15/Screenshot_2022-03-31_at_04.03.43.png
Fig 3-1 Select Resource Group

Click on the create button to create a new resource group called azure-vault-rg
EditorImages/2022/03/31 03:14/Screenshot_2022-03-31_at_02.41.00.png
Fig 3-2 Create Resource Group

Note

When creating a resource in Azure, the naming convention is to end the name of the resource with -rg , this way one can easily identify it as resource group. Same w other names -vault, -secret , -vm, etc

Azure resources tagging allows you to assign a kind of metadata to a resource. Then, you can find all the resources that have the same tag !

A tag is a Key/Value pair. It can be applied to the resource groups or directly on the resources. It is searchable so it can be used to find resources or resource groups using Powershell or Azure Portal.
EditorImages/2022/03/31 03:18/Screenshot_2022-03-31_at_02.43.20.png
Fig 3-3 Resource Group Tag

4. Create Key Vault

Azure Key Vault is a cloud service that provides a secure store for secrets. You can securely store keys, passwords, certificates, and other secrets. Azure key vaults may be created and managed through the Azure portal.

There are several ways to create key vault from the azure portal. From your resource group you can hit the + button to create a new resource or you can search for Key Vault using the search bar.

EditorImages/2022/03/25 05:02/Screenshot_2022-03-17_at_02.54.16.png
Fig 4-1 Search Key Vault

Select the resource group name, enter the key vault name, select region and pricing tier. Then hit the review and create button.

EditorImages/2022/03/31 03:26/Screenshot_2022-03-31_at_02.51.12.png
Fig 4-2 Create Key Vault

Note

Purge protection is an optional Key Vault behavior and is not enabled by default. Purge protection can only be enabled once soft-delete is enabled. It can be turned on via CLI or PowerShell. Purge protection is recommended when using keys for encryption to prevent data loss.

EditorImages/2022/03/31 03:28/Screenshot_2022-03-31_at_03.03.23.png
Fig 4-3 Go to Resource

When you are done creating the key vault click on the Go to resource button. This will take you to the key vault overview page. Take note of the vault uri, this will be used later on the client app. The vault uri value will be used later in step 6.
EditorImages/2022/03/31 03:32/Screenshot_2022-03-31_at_03.05.34.png
Fig 4-4 Key Vault Overview

To check the details or properties of the key vault. Click on properties on the left hand panel.
EditorImages/2022/03/31 04:11/Screenshot_2022-03-31_at_03.54.19.png
Fig 4-5 Key Vault Properties

5. Create Secret

To follow up in this tutorial, you will store your mnemonic in secret. This secret will be retrieved later to sign transaction.

To create secret, click on secret and the + button to generate/import secret.
EditorImages/2022/03/31 03:40/Screenshot_2022-03-31_at_03.06.05.png
Fig 5-1 Create Secret

Enter the secret name and value. Set activation and expiration date and tag then hit the create button.
EditorImages/2022/03/31 03:42/Screenshot_2022-03-31_at_03.53.28.png
Fig 5-2 Create Secret Form

The highlighed secret is the secret name which you will use later in client app. This will be the value for the secret name in the environment variables in step 6.
EditorImages/2022/03/31 03:45/Screenshot_2022-03-31_at_03.56.02.png
Fig 5-3 Secrets

6. Setup Environment Variables

Note

Create .env file at the root of your project to store sensitive information. Your .env file should look like this. The values should not be quoted.

The Purestake client will be used to connect.The API_KEY is gotten from Purestake API. Once you create account, you will have access to the API Key.

The secret name is highlighted in fig 5-3 and the vault uri is highlighted in fig 4-4.

API_KEY = YOUR PURESTAKE API KEY
KEY_VAULT_URI = https://algo-vault.vault.azure.net/
SECRET_NAME =   mnemonic-secret
ALGOD_SERVER = https://testnet-algorand.api.purestake.io/ps2/
PORT = 

7. Get Client Secret From Azure key Vault

This handles connecting to the azure identity and secret client and making a request to get the secret.
// src/VaultSecret.js

// Azure authentication library to access Azure Key Vault
const { DefaultAzureCredential} = require("@azure/identity")
const { SecretClient } = require("@azure/keyvault-secrets")
require('dotenv').config({path: '../.env'})

const getSecret =  async () =>{
  try{
    // Azure SDK clients accept the credential as a parameter
    const credential = new DefaultAzureCredential();
    const client = new SecretClient(process.env.KEY_VAULT_URI, credential)
    const secret =  await  client.getSecret(process.env.SECRET_NAME)
    const value = secret.value
    console.log(value)
    return value
  }catch(err){
    console.log(err)
  }
}
getSecret()
module.exports ={
  getSecret
}

8. Recover Account

This handles recovering of Algorand wallet using the secret from Azure Key Vault.
// src/RecoverAccount.js

  const vault = require('./VaultSecret') 
  const algosdk = require('algosdk')

  const recoverAccount = async () =>{
  const mnomenic = await vault.getSecret()
  const recover =  algosdk.mnemonicToSecretKey(mnomenic)
  console.log(recover.sk)
}

recoverAccount()

9. Create Payment Transaction And Sign With Secret Retrieved From key Vault

Connect your client

//src/Transaction.js

const algodToken = {"X-API-Key": process.env.API_KEY}
const algodServer = process.env.ALGOD_SERVER;
const algodPort = process.env.PORT;
let algodClient = new algosdk.Algodv2(algodToken, algodServer, algodPort);

//src/Transaction.js
The code here handles connecting to the Algorand Purestake API client, creating a payment transaction, Signing the transaction with secret from Azure Key Vault.

const vault = require('./VaultSecret') 
const algosdk = require('algosdk')
require('dotenv').config({path: '../.env'})

  async function paymentTransaction() {
    const mnomenic = await vault.getSecret()
    const account = algosdk.mnemonicToSecretKey(mnomenic)
    const senderAddress = account.addr

    try {

        //Check your balance
        let accountInfo = await algodClient.accountInformation(senderAddress).do();
        console.log("Account balance: %d microAlgos", accountInfo.amount);

        // Construct the transaction
        let params = await algodClient.getTransactionParams().do();
        // comment out the next two lines to use suggested fee
        params.fee = algosdk.ALGORAND_MIN_TX_FEE;
        params.flatFee = true;

        // receiver defined as TestNet faucet address 
        const receiver = "HZ57J3K46JIJXILONBBZOHX6BKPXEM2VVXNRFSUED6DKFD5ZD24PMJ3MVA";
        const enc = new TextEncoder();
        const note = enc.encode("Hello World");
        let amount = 1000000;
        let sender = senderAddress;
        let txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
            from: sender, 
            to: receiver, 
            amount: amount, 
            note: note, 
            suggestedParams: params
        });


        // Sign the transaction
        let signedTxn = txn.signTxn(account.sk);
        let txId = txn.txID().toString();
        console.log("Signed transaction with txID: %s", txId);

        // Submit the transaction
        await algodClient.sendRawTransaction(signedTxn).do();

        // Wait for confirmation
        let confirmedTxn = await algosdk.waitForConfirmation(algodClient, txId, 4);
        //Get the completed Transaction
        console.log("Transaction " + txId + " confirmed in round " + confirmedTxn["confirmed-round"]);
        let string = new TextDecoder().decode(confirmedTxn.txn.txn.note);
        console.log("Note field: ", string);
        accountInfo = await algodClient.accountInformation(senderAddress).do();
        console.log("Transaction Amount: %d microAlgos", confirmedTxn.txn.txn.amt);        
        console.log("Transaction Fee: %d microAlgos", confirmedTxn.txn.txn.fee);
        console.log("Account balance: %d microAlgos", accountInfo.amount);
    }
    catch (err) {
        console.log("err", err);
    }  
  };
  paymentTransaction()

10. Full Code

//src/VaultSecret.js

// Azure authentication library to access Azure Key Vault
const { DefaultAzureCredential} = require("@azure/identity")
const { SecretClient } = require("@azure/keyvault-secrets")
require('dotenv').config({path: '../.env'})

const getSecret =  async () =>{
  try{
    // Azure SDK clients accept the credential as a parameter
    const credential = new DefaultAzureCredential();
    const client = new SecretClient(process.env.KEY_VAULT_URI, credential)
    const secret =  await  client.getSecret(process.env.SECRET_NAME)
    const value = secret.value
    console.log(value)
    return value
  }catch(err){
    console.log(err)
  }
}
getSecret()
module.exports ={
  getSecret
}

// src/RecoverAccount.js

const vault = require('./VaultSecret') 
const algosdk = require('algosdk')

const recoverAccount = async () =>{
const mnomenic = await vault.getSecret()
const recover =  algosdk.mnemonicToSecretKey(mnomenic)
console.log(recover.sk)
}

recoverAccount()

// src/Transaction.js

const vault = require('./VaultSecret') 
const algosdk = require('algosdk')
require('dotenv').config({path: '../.env'})

  async function paymentTransaction() {
    const mnomenic = await vault.getSecret()
    const account = algosdk.mnemonicToSecretKey(mnomenic)
    const senderAddress = account.addr

    try {
        // Connect your client
        const algodToken = {"X-API-Key": process.env.API_KEY}
        const algodServer = 'https://testnet-algorand.api.purestake.io/ps2/';
        const algodPort = "";
        let algodClient = new algosdk.Algodv2(algodToken, algodServer, algodPort);

        //Check your balance
        let accountInfo = await algodClient.accountInformation(senderAddress).do();
        console.log("Account balance: %d microAlgos", accountInfo.amount);

        // Construct the transaction
        let params = await algodClient.getTransactionParams().do();
        // comment out the next two lines to use suggested fee
        params.fee = algosdk.ALGORAND_MIN_TX_FEE;
        params.flatFee = true;

        // receiver defined as TestNet faucet address 
        const receiver = "HZ57J3K46JIJXILONBBZOHX6BKPXEM2VVXNRFSUED6DKFD5ZD24PMJ3MVA";
        const enc = new TextEncoder();
        const note = enc.encode("Hello World");
        let amount = 1000000;
        let sender = senderAddress;
        let txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
            from: sender, 
            to: receiver, 
            amount: amount, 
            note: note, 
            suggestedParams: params
        });


        // Sign the transaction
        let signedTxn = txn.signTxn(account.sk);
        let txId = txn.txID().toString();
        console.log("Signed transaction with txID: %s", txId);

        // Submit the transaction
        await algodClient.sendRawTransaction(signedTxn).do();

        // Wait for confirmation
        let confirmedTxn = await algosdk.waitForConfirmation(algodClient, txId, 4);
        //Get the completed Transaction
        console.log("Transaction " + txId + " confirmed in round " + confirmedTxn["confirmed-round"]);
        let string = new TextDecoder().decode(confirmedTxn.txn.txn.note);
        console.log("Note field: ", string);
        accountInfo = await algodClient.accountInformation(senderAddress).do();
        console.log("Transaction Amount: %d microAlgos", confirmedTxn.txn.txn.amt);        
        console.log("Transaction Fee: %d microAlgos", confirmedTxn.txn.txn.fee);
        console.log("Account balance: %d microAlgos", accountInfo.amount);
    }
    catch (err) {
        console.log("err", err);
    }  
  };
  paymentTransaction()

11. Run Code

Note

To access the secret ensure you are logged in using the azure cli. Type az login.
If you are not logged in and you try to retrieve the secret you will see something like fig 10-1 below.
EditorImages/2022/03/31 05:02/Screenshot_2022-03-31_at_05.29.52.png
Fig 10-1 Unauthorized Error

Upon successful login your response should look like fig 10-2 below
EditorImages/2022/03/31 05:21/Screenshot_2022-03-31_at_06.17.11.png
Fig 10-2 Successful Login

To run the below codes ensure you are in the src folder

Run VaultSecret Code

Run the code using node VaultSecret.js
This will display your vault secret value.
EditorImages/2022/03/31 05:56/Screenshot_2022-03-31_at_06.51.07.png
Fig 10-3 Vault Secret

Run Recover Account Code

Run the code using node RecoverAccount.js. The output will be the mnemonic value you stored in azure key vault secret.
EditorImages/2022/03/31 05:20/Screenshot_2022-03-31_at_06.05.52.png
Fig 10-4 Recover Account Output

Run Transaction Code

Run the code using node Transaction.js
EditorImages/2022/03/26 04:02/Screenshot_2022-03-26_at_04.06.35.png
Fig 10-5 Result

AlgoExplorer

Transaction id VMCTXSOCX3DSQUHMGGVMZOSYT4C6H4CXPN3SYSJ5FI2MO47HUBDA you can check the details of the transaction on the explorer.
EditorImages/2022/03/26 04:02/Screenshot_2022-03-26_at_04.06.58.png
Fig 10-6 AlgoExplorer

12. Clear Resource

When no longer needed, delete the resource group, which deletes the Key Vault and related resources. To delete the resource group through the portal:

Enter the name of your resource group in the Search box at the top of the portal. When you see the resource group used in this tutorial in the search results, select it.Select Delete resource group.
In the TYPE THE RESOURCE GROUP NAME: box type in the name of the resource group and select Delete.

Note

It is important to note that once a secret, key, certificate, or key vault is deleted, it will remain recoverable for a configurable period of 7 to 90 calendar days. If no configuration is specified the default recovery period will be set to 90 days. This provides users with sufficient time to notice an accidental secret deletion and respond. For more information about deleting and recovering key vaults and key vault objects, see Azure Key Vault soft-delete overview.

13. Next step

To learn more on Azure Key Vault and Transactions on Algorand. Checkout the links below;

14. Conclusion

This tutorial covers the basics on how to create Key Vault, sign transactions with retrieved secret value and recover private key.

Warning

This tutorial is intended for learning purposes only. It does not cover error checking and other edge cases. Therefore, it should not be used as a production application.