Documentation Index
Fetch the complete documentation index at: https://sleekplan.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
Sleekplan’s Single Sign-On (SSO) lets users who already have accounts in your application log in to the feedback widget without a separate sign-up step. SSO is built on JSON Web Tokens (JWT), a standard for securely passing authentication data between systems. When a user performs an action that requires authentication — such as voting or submitting feedback — Sleekplan calls $sleek.sso, your server generates a signed token, and Sleekplan accepts it to authenticate the user instantly.
How it works
- A user performs an authenticated action (vote, submit feedback) in the widget.
- The JavaScript SDK calls
$sleek.sso.
- Your server generates a JWT signed with your private SSO key.
- You pass the token back via the
callback() parameter.
- Sleekplan verifies the token and logs the user in seamlessly.
Get your SSO secret key
Find your private SSO key in Settings → Developer inside the Sleekplan dashboard at https://app.sleekplan.com/settings/developer.Your SSO secret key must only ever be used server-side. Never expose it in client-side JavaScript, public repositories, or environment variables that are shipped to the browser. Anyone who obtains the key can generate tokens for any user.
The SSO secret key is available on the Starter and Business plans.
Generate a JWT on your server
Use your language’s JWT library to create a token signed with HMAC SHA-256 (HS256). Replace PRIVATE_SSO_KEY with the key from the previous step. The localUser parameter in each example represents your application’s user record. Node.js
PHP
Python
Ruby
Java
C#/.NET
Install the librarynpm install --save jsonwebtoken
Generate a tokenconst jwt = require('jsonwebtoken');
const key = 'PRIVATE_SSO_KEY';
function createSSOToken(localUser) {
const userData = {
// Required: email address used to uniquely identify the user
mail: localUser.mail,
// Recommended: your internal user ID
id: localUser.id,
// Optional: lowercase username, letters and numbers only
name: localUser.name,
// Optional: URL to the user's avatar image
img: localUser.imgStr,
// Optional: user weighting from 1-10 (e.g. based on MRR)
weight: 4,
// Optional: additional key-value pairs for the user profile
meta: {
companyName: localUser.cName,
},
};
return jwt.sign(userData, key, { algorithm: 'HS256' });
}
Install the librarycomposer require firebase/php-jwt
Generate a tokenuse \Firebase\JWT\JWT;
$key = 'PRIVATE_SSO_KEY';
function createSSOToken($localUser) {
$userData = [
// Required: email address used to uniquely identify the user
'mail' => $localUser['mail'],
// Recommended: your internal user ID
'id' => $localUser['id'],
// Optional: lowercase username, letters and numbers only
'name' => $localUser['name'],
// Optional: URL to the user's avatar image
'img' => $localUser['imgStr'],
// Optional: user weighting from 1-10 (e.g. based on MRR)
'weight' => 4,
// Optional: additional key-value pairs for the user profile
'meta' => [
'companyName' => $localUser['cName'],
],
];
return JWT::encode($userData, $key, 'HS256');
}
Install the libraryGenerate a tokenimport jwt
PrivateKey = 'PRIVATE_SSO_KEY'
def create_sleekplan_token(localUser):
user_data = {
# Required: email address used to uniquely identify the user
'mail': localUser.mail,
# Recommended: your internal user ID
'id': localUser.id,
# Optional: lowercase username, letters and numbers only
'name': localUser.name,
# Optional: URL to the user's avatar image
'img': localUser.img,
# Optional: user weighting from 1-10 (e.g. based on MRR)
'weight': 4,
# Optional: additional key-value pairs for the user profile
'meta': {
'companyName': localUser.cName,
},
}
return jwt.encode(user_data, PrivateKey, algorithm='HS256')
Install the libraryGenerate a tokenrequire 'jwt'
PrivateKey = 'PRIVATE_SSO_KEY'
def createSleekplanToken(localUser)
user_data = {
# Required: email address used to uniquely identify the user
mail: localUser.mail,
# Recommended: your internal user ID
id: localUser.id,
# Optional: lowercase username, letters and numbers only
name: localUser.name,
# Optional: URL to the user's avatar image
img: localUser.img,
# Optional: user weighting from 1-10 (e.g. based on MRR)
weight: 4,
# Optional: additional key-value pairs for the user profile
meta: {
companyName: localUser.cName,
},
}
JWT.encode(user_data, PrivateKey, 'HS256')
end
Install the libraryAdd the jjwt dependency to your pom.xml or build.gradle.Generate a tokenimport 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<>();
// Required: email address used to uniquely identify the user
userData.put("mail", user.email);
// Recommended: your internal user ID
userData.put("id", user.id);
// Optional: lowercase username, letters and numbers only
userData.put("name", user.name);
// Optional: URL to the user's avatar image
userData.put("img", user.avatarURL);
// Optional: user weighting from 1-10 (e.g. based on MRR)
userData.put("weight", 4);
return Jwts.builder()
.setClaims(userData)
.signWith(SignatureAlgorithm.HS256, PrivateKey.getBytes("UTF-8"))
.compact();
}
}
Install the librarydotnet add package System.IdentityModel.Tokens.Jwt
Generate a tokenusing System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;
public class LocalUser {
public string Mail { get; set; }
public string Id { get; set; }
public string Name { get; set; }
}
public static class SsoHelper {
private const string PrivateKey = "PRIVATE_SSO_KEY";
public static string CreateSsoToken(LocalUser localUser) {
var claims = new List<Claim> {
new Claim("mail", localUser.Mail),
new Claim("id", localUser.Id ?? ""),
new Claim("name", localUser.Name ?? ""),
new Claim("weight", "4"),
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(PrivateKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
claims: claims,
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
JWT payload attributes
Sleekplan requires an email address to uniquely identify each user. All other attributes are optional but recommended.| Attribute | Required | Description |
|---|
mail | Yes | Email address of the user. Used as the primary identifier for the Sleekplan user record. |
id | No | Your internal user ID. Highly recommended — allows Sleekplan to match users even if their email address changes. |
name | No | Username. Use lowercase letters and numbers only — no spaces or special characters. |
full_name | No | Full display name shown in the Sleekplan UI. |
img | No | URL to the user’s avatar image. |
weight | No | User weighting from 1 to 10 (e.g., based on MRR). Used for impact scoring on feedback items. |
meta | No | Object of additional key-value pairs stored on the user profile. |
Authenticate the user with the token
Once you have a token, pass it to Sleekplan using the method that fits your integration type.Set window.SLEEK_USER before the widget snippet loads. This is the simplest approach for server-rendered pages where the user is already authenticated when the page is served.<!-- User token — place this BEFORE the widget snippet -->
<script type="text/javascript">
window.SLEEK_USER = {
token: 'YOURTOKEN',
};
</script>
<!-- Sleekplan widget snippet -->
<script type="text/javascript">
window.$sleek = [];
window.SLEEK_PRODUCT_ID = YOUR_PRODUCT_ID;
(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>
Place the window.SLEEK_USER block before the widget snippet. If the snippet loads first, it will not pick up the token.
Call $sleek.setUser() after the SDK has initialized. Use the sleek:init event listener to guarantee the SDK is ready before calling the method.window.document.addEventListener('sleek:init', () => {
$sleek.setUser({ token: 'YOURTOKEN' });
}, false);
Always wrap $sleek.setUser() in the sleek:init listener in SPAs. Calling the method before the SDK finishes loading is the most common cause of authentication failures.
Assign a function to $sleek.sso that fetches a fresh token from your server and passes it to the callback. Sleekplan calls this function only when an unauthenticated user performs an action that requires authentication.$sleek.sso = function(callback) {
fetch('https://yourserver.com/your_sso_endpoint/')
.then(response => response.json())
.then((data) => {
callback({ token: data.ssoToken });
});
};
Enable Force single sign-on in your product settings, then set a custom login URL. When an unauthenticated user visits your feedback board, Sleekplan redirects them to your login page. After authenticating, redirect the user back to the board with the token appended.You can pass the token in any of these ways:| Method | How to pass the token |
|---|
| GET parameter | feedback.yourcompany.com/?sso=YOURTOKEN |
| POST parameter | Form field named sso |
| Request header | Authorization: Bearer YOURTOKEN |
Check the Referer header to determine the correct redirect URL. Ensure your login page is served over HTTPS so the Referer header is sent with the request.
Append the token as a GET parameter to your iframe embed URL:<iframe
src="https://embed-PRODUCTID.sleekplan.app/?sso=YOURTOKEN"
width="100%"
height="600"
frameborder="0">
</iframe>
You can also pass the token via POST parameter or Authorization: Bearer header using the same methods described for standalone pages.