# Single Sign-On (SSO)

If your customers already have user accounts in your application, you can allow them to log in to your feedback widget using our Single Sign-On (SSO) mechanism. The user does not notice this process at all and so you have an even smoother user experience. 🙌

The Single Sign-On is based on a security mechanism that allows Sleekplan to trust the login requests received from your server. Sleekplan only grants access to users who have been authenticated by you. Sleekplan-SSO uses JSON Web Token (JWT), a technology for the secure exchange of user authentication data.

How does it work?

  • When a user performs an action that requires authentication (such as votes, add feedback), the JavaScript SDKs $sleek.sso function is called.
  • You can hook into the function to generate a token on your server using the private SSO key.
  • Pass the generated token back to your app (The $sleek.sso function has a callback() parameter you can pass the generated token to).
  • We will use the token to authenticate the user.

Follow these setps

# 1. Get your SSO secret key

To create a JSON Web Token (JWT), you need the private key for your product. Attention: The private key is only available for the "Starter" and "Business" packages. You can find the private key within the Sleekplan app at Settings -> Developer.

sso

Make sure that no third party gets access to your private key and that you use it only on the server-side in your application. Otherwise, third parties may gain access to your user data.

# 2. Generate a token on your server

Now you need to generate a JSON Web Token on your server. First, install the appropriate JWT library on your server. Below you can find examples for Node.js, PHP, Python, and Ruby. HMAC with SHA-256 ( HS256 ) is used as an encryption method. Your private key from the previous section is required for this. Replace PRIVATE_SSO_KEY with your private key. In the example below, the parameter localUser represents your local user record.

Node.js

Install the JWT library

npm install --save jsonwebtoken

Generate a token

// load jwt library
const jwt = require('jsonwebtoken');
// your private SSO key
const key = 'PRIVATE_SSO_KEY';

function createSSOToken( localUser ) {
    const userData = {
		// Required: The mail address of the user. Required for the login.
		mail: localUser.mail,
		// Optional: Your internal user identification
		id: localUser.id,
		// Optional: Username 
		// (lowercase letters / no special characters or blank spaces)
		name: localUser.name,
		// Optional: URL to user's avatar image
		img: localUser.imgStr,
		// Optional: The weighting of the user
		weight: 4
		// Optional: Additional metadata as key/value pairs
		meta: {
			comapnyName: localUser.cName,
			companyAdress: localUser.cAdress
		}
    }

	// return JSON Web Token
    return jwt.sign(userData, key, { algorithm: 'HS256' });
}
PHP

Install the JWT library

composer require firebase/php-jwt

Generate a token

use \Firebase\JWT\JWT;

// your private SSO key
$key = 'PRIVATE_SSO_KEY';

function createSSOToken( $localUser ) {
	$userData = [
		// Required: The mail address of the user. Required for the login.
		'mail' 	=> $localUser['mail'],
		// Optional: Your internal user identification
		'id' 	=> $localUser['id'],
		// Optional: Username 
		// (lowercase letters / no special characters or blank spaces)
		'name' 	=> $localUser['name'],
		// Optional: URL to user's avatar image
		'img' 	=> $localUser['imgStr'],
		// Optional: The weighting of the user
		'weight' => 4,
		// Optional: Additional metadata as array
		'meta' 	=> [
			'comapnyName' 	=> $localUser['cName'],
			'companyAdress' => $localUser['cAdress'],
		],
	];

	// return JSON Web Token
	return JWT::encode($userData, $key, 'HS256');
}
Python

Install the JWT library

pip install PyJWT

Generate a token

import jwt

# your private SSO key
PrivateKey = 'PRIVATE_SSO_KEY'

def create_sleekplan_token( localUser ):
	user_data = {
		# Required: The mail address of the user. Required for the login.
		'mail': localUser.mail,
		# Optional: Your internal user identification
		'id': localUser.id,
		# Optional: Username 
		# (lowercase letters / no special characters or blank spaces)
		'name': localUser.name,
		# Optional: URL to user's avatar image
		'img': localUser.img,
		# Optional: The weighting of the user
		'weight': 4,
		# Optional: Additional metadata as array
		'meta': {
			'comapnyName': localUser.cName,
			'companyAdress': localUser.cAdress,
		}
	}

	# return JSON Web Token
	return jwt.encode(user_data, PrivateKey, algorithm='HS256')
Ruby

Install the JWT library

# see: https://github.com/jwt/ruby-jwt
gem 'jwt'

Generate a token

require 'jwt'

# your private SSO key
PrivateKey = 'PRIVATE_SSO_KEY'

def createSleekplanToken( localUser )
	UserData = {
		# Required: The mail address of the user. Required for the login.
		mail: localUser.mail,
		# Optional: Your internal user identification
		id: localUser.id,
		# Optional: Username 
		# (lowercase letters / no special characters or blank spaces)
		name: localUser.name,
		# Optional: URL to user's avatar image
		img: localUser.img,
		# Optional: The weighting of the user
		weight: 4,
		# Optional: Additional metadata as array
		meta: {
			comapnyName: localUser.cName,
			companyAdress: localUser.cAdress,
		}
	}

	# return JSON Web Token
	JWT.encode(UserData, PrivateKey, 'HS256')
end
Java

Install the JWT library

# see: https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt/0.7.0

Generate a token

import java.util.HashMap;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

public class CreateSSOToken {
  private static final String PrivateKey = "PRIVATE_SSO_KEY";

  public static String createToken(User user) throws Exception {
    HashMap<String, Object> userData = new HashMap<String, Object>();

    // Required: The mail address of the user. Required for the login.
    userData.put("mail", user.email);
    // Optional: Your internal user identification
    userData.put("id", user.id);
    // Optional: Username 
		// (lowercase letters / no special characters or blank spaces)
    userData.put("weight", user.name);
    // Optional: URL to user's avatar image
    userData.put("img", user.avatarURL);
    // Optional: The weighting of the user
    userData.put("img", user.avatarURL);
    // Optional: Additional metadata as key/value pairs
    userData.put("meta", [META]);

    return Jwts.builder()
               .setClaims(userData)
               .signWith(SignatureAlgorithm.HS256, PrivateKey.getBytes("UTF-8"))
               .compact();
  }
}

Sleekplan requires an email address to uniquely identify the user. In addition to the required attributes listed in the table below, you can also pass additional user and company profile data as needed. This data is synchronized between your user management system and Sleekplan.

Attribute Required Description
mail x Email address of the user who is logged in. Used to uniquely identify the user record.
id - Your internal user identification. It allows you to easily identify users. If provided, this will also be used to identify a user. (Highly recommended, so that users can be identified even if the email address has been changed)
name - Name of the user. The Sleekplan user profile is created or updated according to this value. Use only lowercase letters (a-z), numbers (0-9), and no spaces.
full_name - Full name of the user.
img - URL to the user's avatar image.
weight - Assign a weighting (1-10) to a user. You can set this based on your customers' MRR, for example.
meta - An object or array of key-value pairs to be set for the user.

# 3. Authenticate user with the token

After you have created a token for your user, you can easily sign the user in to the widget, standalone website or iframe. Depending on your workflow, you can pass the SSO token in different ways. We have summarized the most common methods for you below.

# 3.1 Widget - Set the token

# Option 1: On page load

In the snippet below, replace the example token (XXXXXXX) in the window.SLEEK_USER object with your own variable for user token.

window.SLEEK_USER = {
    token: 'XXXXXXX', 
}

Copy and paste the snippet before the tag on every page you want the Sleekplan widget to appear for logged-in users. Make sure you place the window.SLEEK_USER object before the widget snippet, like shown below.

 
 
 
 
 
 




<!-- User Token -->
<script type="text/javascript">
window.SLEEK_USER = {
    token: 'XXXXXXX', 
}
</script>

<!-- Sleekplan Widget Code -->
<script type="text/javascript">window.$sleek=[];window.SLEEK_PRODUCT_ID=XY;(function(){d=document;s=d.createElement("script");s.src="https://client.sleekplan.com/sdk/e.js";s.async=1;d.getElementsByTagName("head")[0].appendChild(s);})();</script>

# Option 2: On single-page apps

Once you have the $sleek SDK installed then you simply need to pass a JSON Web Token using the setUser( data ) method. Simply call the method and pass an object with your generated token (ie. {token: 'YOURTOKEN'}). You can find more information for the setUser-Method here: JavaScript SDK -> Setup user

$sleek.setUser ( {
    token: 'XXXXXXX', 
} );

Does not work?

Is the $sleek SDK already loaded? A common problem that some users encounter when trying to call a method of the $sleek SDK is that the library is not yet fully loaded. To avoid this, you can simply set up a listener on the sleek:init event that will wait until the $sleek SDK is initialized before loading the code.

window.document.addEventListener('sleek:init', () => {
	$sleek.setUser ( {token: 'XXXXXXX'} );
}, false);

# Option 3: Asynchronously

Whenever an unauthenticated user performs an action that requires authentication (such as voting, commenting, etc), the SDK method $sleek.sso is called. In your applications JavaScript code, you can assign a function to the sso property as shown below.

$sleek.sso = function( callback ) {...};

The function must have a callback parameter that passes the JSON Web Token (generated on your server) back to the widget. Now you finally have to get the token from your server. To return the token, an object with a token parameter needs to be passed to the callback({token: 'XXXXXXX'});.







 

 



$sleek.sso = function( callback ) {
	// load the current user token from your server side script
	fetch('https://yourserver.com/your_sso_script/')
		.then(response => response.json())
		.then((data) => {
            // get your userToken
			let userToken = data.ssoToken;
			// return the generated token to the widget
			callback( {token: userToken} );
		});
};

# 3.2 Standalone page

To use single sign-on with your standalone website it's recommened to enable the 'Force single sign-on (SSO)' option. Provided the option has been activated you can specify a custom login url. Instead of asking users to sign up for a user account, we'll send them to your website to log in to your application.

After doing so, you need to send a request to your server to generate a single sign-on token for them, and then redirect them back to your board. With the redirect you need to pass the generated token as an query parameter naemd sso (e.g. feedback.yourcompany.com/?sso=YOURTOKEN)

To get the correct redirect URL you best check the Refere header. Make sure that the redirect login url started with https://.. so that the Refere header is sent as well.

You can pass the Single sign-on token as GET-paremeter, POST-parameter or send it via the request Header

Method Parameter
GET sso
POST sso
HEADER Authorization: Bearer <sso token>

# 3.3 Iframe

Please note the procedure described above for standalone websites. Once you have created the token, you can simply append it as a GET parameter to your iframe url (e.g. embed-PRDUCTID.sleekplan.app/?sso=YOURTOKEN) or using one of the other methods to pass the token.