Generating Viewer Tokens

Typically Viewer Tokens are fetched from the ESAPI, but you can implement the algorithm yourself if that is cumbersome for your usecase.

This page includes a step-by-step explanation of the Viewer Token generation algorithm and sample code for servers in different languages. You don’t need to have a detailed understanding of the algorithm to be able to use the sample code and start using the Plans JavaScript SDK.

Additionally, we provide an online Viewer Token generator that you can use during development to validate your generation code, or to help you throw something together quickly.

Generation Algorithm

  1. Generate the correct string to sign. This string has the following structure and order of parameters:

     <version>:<access>:<resourceCode>:<partnerCode>:<expiry>
    

    All parameters are mandatory.

    Header Value Description
    version v3 The version number of the Viewer Token format
    access allAreas allAreas allows access to everything in the plan. In future support will be added to exclude content covered by private zones, for now allAreas is the only option.
    resourceCode string Client, campus, building, floor or plan code. Must be a child of the Partner Code. Plan code can be either a site plan or floor plan code.
    partnerCode string Partner Code. Must be accessible by the API Key
    expiry string Unix timestamp in seconds
    write true | false Allows making changes to plans if true

    Examples

    • Access only plan code pln_a480s881dgmkh1m36up6g6f0w (a site plan or a floor plan), which belongs to partner code ptnr_cadr0g675rbk0fv03fm5fewz7, expiring at 2145916800, read and write
      becomes v3:allAreas:pln_a480s881dgmkh1m36up6g6f0w:ptnr_cadr0g675rbk0fv03fm5fewz7:2145916800:true

    • Access a siteplan and all floor plans of campus code camp_e5borhpj2hdp6v6ktjmzdqki8, which belongs to partner code ptnr_cadr0g675rbk0fv03fm5fewz7, expiring at 2145916800, readonly
      becomes v3:allAreas:camp_e5borhpj2hdp6v6ktjmzdqki8:ptnr_cadr0g675rbk0fv03fm5fewz7:2145916800:false

    • Access all floor plans in building code bld_qg24o7wcf3p1wvib2147t8dwq, which belongs to partner code ptnr_cadr0g675rbk0fv03fm5fewz7, expiring at 2145916800, readonly
      becomes v3:allAreas:bld_qg24o7wcf3p1wvib2147t8dwq:ptnr_cadr0g675rbk0fv03fm5fewz7:2145916800:false

  2. Ensure the string is UTF-8 encoded. Signing algorithms work on bytes, so it’s important that the string is represented with the correct byte encoding.

  3. Generate an HMAC, using the SHA256 hashing algorithm and your UTF-8 encoded API secret as the key.

  4. Create a Base64 digest of that HMAC.

  5. URL-encode the Base64 digest to create the SAS token. It doesn’t matter whether your URL encoding uses uppercase or lowercase letters when escaping characters (e.g turning / into %2F vs %2f).

  6. Generate the correct string to encode. This string has the following structure and order of parameters:

     <string to sign>,<apiKey>,<sasToken>
    
  7. Base64 encode the string to encode. This is the Viewer Token!

Sample Code

C#

using System;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Web;

public class ViewerTokenGenerator
{
    private static string API_KEY = "YOUR_API_KEY";
    private static string API_SECRET = "YOUR_API_SECRET";
  
    public static string Generate(
        string partnerCode,
        string resourceCode, 
        string access, // `allAreas`
        long expiry,
        bool write
    )	{
        // 1. Generate the correct string to sign.
        var parts = new []{
            "v3",
            access,
            resourceCode,
            partnerCode,
            expiry.ToString(),
            write ? "true" : "false"
        };
        var stringToSign = string.Join(":", parts);
        
        // 2. Ensure the string is UTF-8 encoded.
        var stringToSignUTF8 = Encoding.UTF8.GetBytes(stringToSign);
        
        // 3. Generate an HMAC, using your UTF-8 encoded API secret as the key.
        HMACSHA256 algorithm = new HMACSHA256(Encoding.UTF8.GetBytes(API_SECRET));
        var digestBytes = algorithm.ComputeHash(stringToSignUTF8);
        
        // 4. Create a Base64 digest of that HMAC.
        var base64Digest = Convert.ToBase64String(digestBytes);
      
        // 5. URL-encode the Base64 digest.
        var sasToken = HttpUtility.UrlEncode(base64Digest);

        // 6. Generate the correct *string to encode*.
        var viewerTokenParts = new []{
            stringToSign,
            API_KEY,
            sasToken
        };
        var stringToEncode = string.Join(",", viewerTokenParts);

        // 7. Base64 encode the *string to encode*.
        var viewerToken = Convert.ToBase64String(Encoding.UTF8.GetBytes(stringToEncode));
        
        return viewerToken;
    }
}

Node.js

const crypto = require('crypto');

const API_KEY = 'YOUR_API_KEY';
const API_SECRET = 'YOUR_API_SECRET';

function generateViewerToken (
    partnerCode, // string
    resourceCode, // string
    access, // string `allAreas`
    expiry, // number
    write // boolean
) {
    // 1. Generate the correct string to sign.
    var stringToSign = [
        'v3',
        access,
        resourceCode,
        partnerCode,
        expiry.toString(),
        write.toString()
    ].join(':')

    // 2. Ensure the string is UTF-8 encoded.
    var stringToSignUTF8 = Buffer.from(stringToSign, 'utf8')

    // 3. Generate an HMAC, using your UTF-8 encoded API secret as the key.
    var algorithm = crypto.createHmac('sha256', Buffer.from(API_SECRET, 'utf8'))
    algorithm.update(stringToSignUTF8)
    
    // 4. Create a Base64 digest of that HMAC.
    var base64Digest = algorithm.digest('base64')

    // 5. URL-encode the Base64 digest.
    var sasToken = encodeURIComponent(base64Digest)

    // 6. Generate the correct *string to encode*.
    var stringToEncode = [
      stringToSign,
      API_KEY,
      sasToken
    ].join(',')

    // 7. Base64 encode the *string to encode*.
    var viewerToken = Buffer.from(stringToEncode, 'utf-8').toString('base64')

    return viewerToken
}

Python 3

import base64
import datetime
import hashlib
import hmac
import json
import urllib.parse

API_KEY = 'YOUR_API_KEY'
API_SECRET = 'YOUR_API_SECRET'

def generate_viewer_token(partner_code, resource_code, access, expiry, write):
    """ Generate a Viewer Token.

    @param partner_code str
    @param resource_code str
    @param access string `allAreas`
    @param expiry int
    @param write bool
    """

    # 1. Generate the correct string to sign.
    params = ['v3', access, resource_code, partner_code, str(expiry), 'true' if write else 'false']
    string_to_sign = ":".join([p for p in params])

    # 2. Ensure the string is UTF-8 encoded.
    string_to_sign_utf8 = string_to_sign.encode('utf-8')

    # 3. Generate an HMAC, using your UTF-8 encoded API secret as the key.
    sig = hmac.new(bytes(API_SECRET, 'latin-1'), msg=bytes(string_to_sign, 'latin-1'), digestmod=hashlib.sha256).digest()

    # 4. Create a Base64 digest of that HMAC.
    base64_digest = base64.b64encode(sig).decode('utf8')

    # 5. URL-encode the Base64 digest.
    sas_token = urllib.parse.quote(base64_digest)

    # 6. Generate the correct *string to encode*.
    params = [string_to_sign, API_KEY, sas_token]
    string_to_encode = ",".join([p for p in params])

    # 7. Base64 encode the *string to encode*.
    viewer_token = base64.b64encode(bytes(string_to_encode, 'latin-1')).decode('utf8')
    
    return viewer_token

PHP

define('API_KEY', 'YOUR_API_KEY');
define('API_SECRET', 'YOUR_API_SECRET');

/**
  * Generate a Viewer Token
  * @param string $partnerCode Partner Code
  * @param string $resourceCode Client/Campus/Building/Floor/Plan code
  * @param string $access `allAreas`
  * @param int $expiry Unix timestamp expiry date for the token
  * @param bool $write True to allow changes to plans
  * @return 
  */
function generateViewerToken($partnerCode, $resourceCode, $access, $expiry, $write) {
    // 1. Generate the correct string to sign.
    $stringToSign = implode(':', [
        'v3',
        $access,
        $resourceCode,
        $partnerCode,
        $expiry,
        $write ? 'true' : 'false'
    ]);
    
    // 2. Ensure the string is UTF-8 encoded.
    $stringToSignUTF8 = utf8_encode($stringToSign);

    // 3. Generate an HMAC, using your UTF-8 encoded API secret as the key.
    $hmac = hash_hmac('sha256', $stringToSignUTF8, API_SECRET, true);
    
    // 4. Create a Base64 digest of that HMAC.
    $base64Digest = base64_encode($hmac);

    // 5. URL-encode the Base64 digest.
    $sasToken = urlencode($base64Digest);

    // 6. Generate the correct *string to encode*.
    $stringToEncode = implode(',', [
      $stringToSign,
      API_KEY,
      $sasToken
    ]);

    // 7. Base64 encode the *string to encode*.
    $viewerToken = base64_encode($stringToEncode);

    return $viewerToken;
}