# 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 acallback()
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.
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 |
---|---|---|
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.