SolarNode External Login - SolarNetwork/solarnetwork GitHub Wiki

Externally managed SolarNode setup login

This guide describes how you can provide credentials and log into SolarNode via a web API on SolarNode. This can be used to integrate the SolarNode GUI into another web application. See the SolarNode External Login Demo application that uses this API to try this out with your own node.

Overview

The external login process works like this:

  1. Request a login key for a specific user.
  2. Use the returned key data to AES encrypt the user's password.
  3. Log the user in using the encrypted password.

The AES-256 encryption algorithm is used, in CBC mode with PKCS#7 padding. This is a common and widely supported scheme.

Generate login key

The first step required is to generate a login key for the SolarNode user you want to log in as. This is accomplished by performing a GET request to the /pub/session/key endpoint.

GET /pub/session/key
username The SolarNode username to authenticate as.
salt Exactly 12 bytes of random data, encoded into a Base64 string.

For example:

/pub/session/key?username=example%40localhost&salt=LokLfTFaO1yj4MzK

This will return a standard SolarNetwork API response object, where the data property is an object with the following properties:

Property Type Description
iv string Base64 encoded bytes used as the initialisation vector the AES cipher.
key string Base64 encoded key used to encrypt the password.
{
    "success": true,
    "data": {
        "iv": "9a9mFuAUCzatjL+jC5Gk8A==",
        "key": "yP/cGXqvqtW4GMaqLULKIscryEw25umA8ahMkLtwEBU="
    }
}

⚠️ Note: the key is only valid for a short amount of time. Each time you want to log in using this API, you must generate a new key and then call the /pub/session/login endpoint immediately afterwards.

Encrypt password

The next step is to encrypt the user's password using the AES-256 algorithm, in CBC mode with PKCS#7 padding. The iv value returned from /pub/session/key in the previous step (decoded from Base64) is used as the AES initialisation vector, and the key value (also decoded from Base64) is the key.

In pseudo-code, the process looks like this:

import { Base64Decode, Base64Encode, AESEncrypt } from "super-crypto-lib";

const username = "example@localhost";
const password = "supersecret";

// keyData is returned from the /pub/session/key API
const keyData = {iv:"9a9mFuAUCzatjL+jC5Gk8A==", key:"yP/cGXqvqtW4GMaqLULKIscryEw25umA8ahMkLtwEBU="};

// decode IV & key
const key = Base64Decode(keyData.key);
const iv = Base64Decode(keyData.iv);

// encrypt password
const encryptedPassword = Base64Encode(AESEncrypt(iv, key, password));

// now encryptedPassword == "RnUyxgKor9/63LKpQu2jSA=="

Login

The final step is to log in. You'll need to pass the encrypted password generated in the previous step, and a "salted" username.

This is accomplished by performing a GET request to the /pub/session/login endpoint. Note this endpoint will return HTML, and is designed to be loaded directly by a browser.

GET /pub/session/login
username The same salt value previously passed to the /pub/session/key endpoint concatenated with the UTF-8 bytes of the SolarNode username to authenticate as, all encoded into a Base64 string.
password The encrypted password as outlined in the previous section, encoded into a Base64 string.

In pseudo-code, the process looks like this:

import { Base64Decode, Base64Encode, Utf8Bytes } from "super-crypto-lib";

// encryptedPassword calculated in previous section
const encryptedPassword == "RnUyxgKor9/63LKpQu2jSA==";

// same salt value as passed to /pub/session/key at start of this process 
const salt = "LokLfTFaO1yj4MzK";

const username = "example@localhost";
const saltyUsername = Base64Encode(Base64Decode(salt).concat(Utf8Bytes(username)));

const loginUrl = "http://solarnode/pub/session/login?username="
    + encodeURIComponent(saltyUsername)
    + "&password="
    + encodeURIComponent(encryptedPassword);

Conclusion

Assuming the login credentials are correct, then you should have successfully logged into SolarNode at this point.

External Login Demo Screenshot

⚠️ **GitHub.com Fallback** ⚠️