Stateless SSO

The idea of Stateless SSO is simple: Each time the <hyvor-talk-comments> element loads, you will let us know if the user is logged in or not. If yes, you will also send the user's data along with other configuration. An HMAC hash is used to validate the authenticity of user data.

Requirements

Enabling Stateless SSO

To enable Stateless SSO on your website, turn on SSO from the Console, and select the type Stateless. A Private key will be generated for you. You will need this key to generate the HMAC hash in the next steps.

Login URL

If you have a login page, set the Login URL to the URL of your login page. This will be used to redirect users when they click on the login button. If you have a login popup, keep the Login URL option empty and use the auth:login:clicked event to open the popup using Javascript.

Setting up the Front-end

To set up Stateless SSO, you have to set sso-user and sso-hash attributes in the <hyvor-talk-comments> element.

If you are using HTML installation,

<hyvor-talk-comments
    ...other-props

    sso-user="base-64 encoded, JSON-encoded user data"
    sso-hash="HMAC hash"
></hyvor-talk-comments>

If you are using JS installation,

const comments = document.createElement("hyvor-talk-comments");
comments.setAttribute('sso-user', "base-64 encoded, JSON-encoded user data");
comments.setAttribute('sso-hash', "HMAC hash");

Sync vs Async Integrations

If your website is rendered using templates with back-end processing (for example, using PHP templates), you can calculate the data and hash at the time of template rendering, and then print them directly in the HTML code

<hyvor-talk-comments
    ...other-props

    sso-user="<?= $userData ?>"
    sso-hash="<?= $hash ?>"
></hyvor-talk-comments>

If you have a Single-Page application, you will need to create a new API endpoint (ex: /hyvor-talk-sso) to generate the data and hash in your backend. Then, call that endpoint to get the hash and then render the <hyvor-talk-comments> element asynchronously.

const comments = document.createElement("hyvor-talk-comments");

const ssoData = await getHyvorTalkSsoData(); // calling the API

comments.ssoUser = ssoData.user;
comments.ssoHash = ssoData.hash;

// finally add the element to DOM
document.body.appendChild(comments);

Generating User Data and the Hash

Whether you generate user data and the hash synchronously or asynchronously, the process will always be the same. In this documentation, we will use Javascript as most web developers are familiar with it. You can find code examples for other languages in this repository.

Step 1: Check if the user is logged in

if (isUserLoggedIn()) {

}

Handling Unauthenticated Users

If the user is not logged in, you can stop doing any other processing. In the comments element, set sso-user and sso-hash to empty values:

  • sso-user=”” in HTML
  • comments.setAttribute('sso-user', null) in JS (or any other empty value)

Step 2: Create the User Data Object

You may already have the current user’s data in your system as an object or model. The next step is to convert that into an object that Hyvor Talk "understands".

// this is your system's user
const user = getUser();

// create an object that Hyvor Talk understands
let userData = {
    timestamp: Math.floor(Date.now() / 1000),

    id: user.id,
    name: user.fullname,
    email: user.email,
    picture_url: user.picture,
    website_url: user.website,
    bio: user.bio,
    location: user.location,

    badge_ids: [1,2]
}

User Data Object

Key Description Type Status Max Length
timestamp UNIX timestamp in seconds when the object was created. integer required
id A unique ID saved in your database for each user. This is used to identify each user by Hyvor Talk. integer or string required 128
name User's display name string required 50
email User's email string required 256
picture_url Absolute URL of the user's profile picture string optional 1024
website_url Absolute URL of the user's profile or website string optional 1024
bio User’s bio string optional 255
location User’s country or city. string optional 50
badge_ids An array of badge IDs to assign to this user integer[] optional max 3 IDs

Data Length

id, email, picture_url, and website_url should not exceed the maximum length. This will show an error message and prevent the embed from loading. If name, bio, or location exceeds the maximum length, they will be trimmed.

Data Privacy

The name, picture_url, website_url, bio, and location will be shown publicly. The email will only be used to send email notifications on replies and mentions.

Step 3: JSON and Base64 encode the User Data

Next, JSON-encode and then base64-encode the user data.

// 1. JSON encoding
userData = JSON.stringify(userData);

// 2. Base64 encoding
userData = Buffer.from(userData).toString('base64');

Why JSON and Base64?

JSON encoding makes transmitting data through networks easy. Base64 encoding makes it possible to print out this data into HTML code. Therefore, JSON and base64 encoding is for convenience, not for security.

Step 4: Generating the Hash

The next step is to generate an HMAC hash from userData. For this, we need the private key you received when setting up Stateless SSO in the Console. We use HMAC SHA 256.

Here we will use the crypto-js Javascript library. However, most programming languages have HMAC hashing functions in-built.

const CryptoJS = require('crypto-js');
const hash = CryptoJS.HmacSHA256(userData, YOUR_PRIVATE_KEY);

Why the hash?

In order to securely connect SSO, we need to make sure that we receive the SSO user data generated by you, not someone else. The hash ensures this. Because the private key is only shared between you and us, no one else can generate a valid HMAC hash. So, when we render the <hyvor-talk-comments> element, we check if the user data and hash match. And, only then, do we log in the user.

Why timestamp in the user object?

This value allows us to expire old objects. Our system will not accept a timestamp older than 7 days, giving enough time for a single browser session, and also limiting the risk of replay attacks. We recommend generating a new hash with a new timestamp on every page load. Or, if you have a single-page application, on every initial load.

Here’s the complete code in JS (Node):

if (isUserLoggedIn()) {

   // this is your system's user
   const user = getUser();

   // create an object that Hyvor Talk understands
   let userData = {
        id: user.id,
        name: user.fullname,
        email: user.email,
        picture_url: user.picture,
        website_url: user.website
    }

    // 1. JSON encoding
    userData = JSON.stringify(userData);

    // 2. Base64 encoding
    userData = Buffer.from(userData).toString('base64');

    // HMAC SHA256 hash
    const CryptoJS = require('crypto-js');
    const hash = CryptoJS.HmacSHA256(userData, YOUR_PRIVATE_KEY);

}

Step 5: Set HTML Attributes

The last step is to set the attributes in the <hyvor-talk-comments> element.

Security