Skip to content
Feeblo Docs
Esc
navigateopen⌘Jpreview
On this page

Widget SSO

Sign identity tokens on your server and sign users into your public board without a second login.

Anyone can type Feeblo.identify({ id: "u_1" }) into a browser console. A signed token is what makes an identity trustworthy: you sign a JWT on your server with your organization’s secret, Feeblo verifies it against the same secret, and posts submitted with it get attached to a real contact.

The same token doubles as a login for your public feedback board.

Signing the token

Find your organization secret in Settings → Security. Sign with HS256 on your server, never in the browser:

import jwt from "jsonwebtoken";

const now = Math.floor(Date.now() / 1000);

const token = jwt.sign(
  {
    // Required claims
    sub: user.id,                     // your user's ID in your system
    aud: process.env.FEEBLO_ORG_ID,   // your Feeblo organization ID
    exp: now + 10 * 60,               // expires in 10 minutes

    // Profile claims
    email: user.email,
    name: user.name,

    // Optional
    iss: "https://app.yourdomain.com", // identifies who minted the token
    iat: now,
    avatar: user.avatar,

    // Optional. Keys must match custom attributes you defined in Feeblo;
    // unmatched keys are ignored.
    customFields: {
      plan: "enterprise",
    },

    companies: [
      {
        id: company.id,       // required
        name: company.name,   // required
        // avatar: "...",     // optional
        customFields: {
          industry: "SaaS",  // optional, org-defined
        },
      },
    ],
  },
  process.env.FEEBLO_ORG_SECRET,
  { algorithm: "HS256" }
);

Claims reference

Claim Required Notes
sub yes Your user’s ID in your system
aud yes Your Feeblo organization ID
exp yes Unix expiration timestamp
iat no Unix issued-at timestamp
iss no Who minted the token, e.g. your app’s URL
email yes
name yes
avatar no Image URL
customFields no Mapped to your organization’s contact attributes; unknown keys ignored
companies no Array of company objects
companies[].id yes Per company
companies[].name yes Per company
companies[].avatar no Per company
companies[].customFields no Mapped to your organization’s company attributes

Passing the token to the SDK

Feeblo.identify({
  id: user.id,
  email: user.email,
  name: user.name,
  token,
});
<FeebloProvider organizationId="org_123" user={{ ...identity, token }}>
  <App />
</FeebloProvider>

Signing users into your public board

Your public feedback board accepts the same token as a login. Two ways to hand it over:

Let the SDK decorate your links (recommended). Mark any anchor pointing at your board:

<a href="https://feedback.yourdomain.com" data-feeblo-link>Give feedback</a>

When an identified user interacts with that link, the SDK appends their current token automatically. It goes in the URL fragment (#ssoToken=...) rather than the query string, so it never reaches server logs, proxies, or the Referer header. This only works after identify ran with a token.

Redirect with the token in the URL. Send the user to:

https://feedback.yourdomain.com/?ssoToken=JWT

The board reads the token and strips it before rendering.

Rotating the organization secret

Rotate the secret in Settings → Security whenever someone with access leaves or you suspect a leak. Tokens signed with the old secret fail verification from that moment on, so deploy your updated secret right after you rotate. Rotate during low traffic to keep the gap painless.

Short-lived tokens make rotation cheap: with 10-minute tokens, any damage from an exposed secret lasts 10 minutes.

Troubleshooting

Tokens get rejected

Work through this list:

  • You signed with the current organization secret, not a rotated-out one.
  • aud equals your organization ID exactly.
  • sub, email, name, and exp are all present.
  • exp hasn’t passed on the server’s clock. Compare clocks if rejections cluster around token birth and expiry times.

Next steps

Was this page helpful?