$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.
1
Get your SSO secret key
Find your private SSO key in Settings → Developer inside the Sleekplan dashboard at https://app.sleekplan.com/settings/developer.
The SSO secret key is available on the Starter and Business plans.
2
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 libraryGenerate a token
JWT payload attributes
Sleekplan requires an email address to uniquely identify each user. All other attributes are optional but recommended.3
Authenticate the user with the token
Once you have a token, pass it to Sleekplan using the method that fits your integration type.
- Widget — on page load
- Widget — single-page apps
- Widget — async / on-demand
- Standalone page
- Iframe
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.Companies and teams
Add agroups array to the token to mirror the accounts in your own system (a company, a team, or a workspace) so admins can see feedback, votes and satisfaction rolled up by account instead of only by individual user. Groups are created and updated automatically from this claim.
Groups require the Business plan or higher. On lower plans a
groups claim is accepted and silently ignored, so nothing appears in the dashboard until the workspace upgrades. If groups aren’t showing up, check the plan first.id is required on each entry. Everything else is optional and defaulted.
string
required
Your identifier for the account. This is what Sleekplan matches on across sign-ins, so treat it as immutable: changing it creates a different group rather than renaming the existing one. Up to 255 characters.
string
Display name. If omitted, the dashboard shows the identifier instead. Up to 255 characters.
string
default:"company"
A free-form label such as
company, team, or workspace. Normalized on write, see Type normalization below.integer
default:"1"
A 0 to 10 prioritization weight for the account’s votes, clamped to that range. The group equivalent of the user-level
weight above.integer
default:"0"
Monthly recurring revenue for the account, in whole units of your workspace’s currency. No minor units, no currency conversion.
object
Flat key/value custom data, string values only. Up to 20 keys per group, each key and value up to 255 characters.
Sync is additive, always
A sign-in creates and updates groups and memberships. It never removes a membership, even for a group that used to appear in the token and no longer does. Removing a customer from a group is an explicit action an admin takes in the dashboard, from the group’s Members tab or the customer’s Groups tab. This is deliberate: groups can also be populated by an external CRM sync running independently of your login flow, and a sign-in that silently pruned what another integration just wrote would destroy data no one asked it to touch.Only the fields you actually send are touched
Resyncing an account only updates the keys present in that entry. A token that sends{ id: 'acme-inc' } on every login updates nothing but the membership itself: it can never blank an mrr or a custom meta key an admin later set by hand. Sending the same entry twice in a row writes nothing the second time.
There is one deliberate asymmetry in how metadata is handled:
- SSO sync merges a
metaobject into the group’s existing metadata. A key an admin added by hand survives a later sign-in that doesn’t mention it. - An admin’s edit in the dashboard replaces the whole metadata object. The admin is looking at the full panel and saving what they see, so a key they delete there stays deleted, even though a later sync would have merged it back if the token happened to carry it.
Limits
A bad
groups claim never fails the sign-in. Entries past the tenth are dropped, and a malformed entry (not an object, or missing id) is skipped on its own without discarding the rest of the array. Beyond that the two bounds behave differently, so it is worth knowing which is which:
- An over-length
idornameskips that entry entirely. It is not truncated, because a truncated identifier would silently create or match the wrong group. - An over-length
typeormetakey/value is truncated, andweightandmrrare clamped into range.
Type normalization
Atype is lowercased, its whitespace becomes a hyphen, anything outside a-z, 0-9, _ and - is stripped, repeated hyphens collapse to one, and the result is capped at 64 characters. Key Account becomes key-account. An input that normalizes to nothing, or an omitted type, falls back to company.
This exists so Company, company and Company from three different sessions land in the same bucket. Without it a workspace could spend its entire type budget on casing variants of the same account type and see its own numbers split across them.
When groups appear
Sync runs at sign-in, and sign-in only happens when the widget has no existing session, exactly likeweight and meta already work. A change on your side (a renamed account, a new team in the token) shows up the next time that user starts a fresh session, not on their next page view within an existing one.
Sync is also dispatched to a background worker rather than run inline, so a sign-in never waits on it and never fails because of it. In practice a synced group or membership can take a moment to appear after the session starts.
User setup
The
$sleek.setUser() method and the rest of the user payload.Companies and teams in the dashboard
How groups look for your team once they start arriving.
