Share your own site's authentication with Tender

Updated 10 Oct, 2026 01:07 AM in Customizing your Tender site

If your customers already log in to your own app, single sign-on (SSO) lets them use Tender without a second account or password. Your app tells Tender who someone is with a multipass: a small encrypted message holding their email address and name. Tender logs them in, creating their Tender profile the first time.

Single sign-on is set up by your developers, and depends on your plan.

Turning it on

  1. Go to Account & Settings › Extras and click Single Sign-On (under Advanced) in the sidebar.
  2. Click On in the Single Sign-On box.
  3. Fill in the box:
    • Login URL: your app's login page. Tender's Log in links go there instead of Tender's own login page, with a to parameter added saying which Tender page to come back to, for example https://app.example.com/login?to=https://help.example.com/discussions. Customers can no longer log in or sign up on Tender itself.
    • Logout URL (optional): where Tender sends people after they log out of Tender, such as your app's logout page.
  4. Click Save your changes.

The box also shows the two values your developers need: the Site key (your site's name in its tenderapp.com address) and the SSO API key. Keep the SSO API key secret, like a password: anyone with it can log in to your Tender as anyone.

The Single Sign-On settings, with Login URL, Logout URL, SSO API key and Site key

Each click on On (even when single sign-on is already on) makes a new SSO API key, and so does turning it off and on again. Multipasses made with the old key stop working, so update your app when that happens.

How a login works

  1. A customer clicks Log in on Tender, and lands on your Login URL with ?to=<the Tender page>.
  2. Your app logs them in as usual (or sees they already are).
  3. Your app makes a multipass for them and sends them back to the to address with sso=<multipass> added, for example https://help.example.com/discussions?sso=....
  4. Tender reads the multipass, logs them in, and shows the page.

You can also link straight to any Tender page with ?sso=<multipass> from inside your app, so customers who are logged in to your app arrive on Tender already logged in.

Your support staff can use single sign-on too, if they have accounts in your app with the same email address. They can also keep logging in with their Tender password at your site's /login page.

What goes in a multipass

A multipass is a JSON object:

{
  "email": "jane@example.com",
  "name": "Jane Doe",
  "unique_id": "42",
  "expires": "2026-10-09T12:05:00Z"
}
Key
email The customer's email address. Required.
expires When this multipass stops working. Required: use a time a few minutes ahead, in UTC. ISO 8601 (2026-10-09T12:05:00Z) is simplest.
name The name Tender shows. display_name, username or login also work.
unique_id The customer's id in your app. Tender uses it to recognise them, so they keep the same Tender profile even if their email address changes. Without it, Tender uses the email address. guid also works.
alternate_id Used to find the customer when no one has their unique_id yet, for example their email address when you start sending unique_ids.
trusted true to never check this customer's comments for spam.
beta, important true or false to give the customer beta or important access.
company_name or company_id Puts the customer in that company, creating it if the name is new (on plans with companies).
to An address on your Tender site to send the customer to after logging in.

If your app has test or staging copies, add a prefix to their unique_ids (staging-42) so they don't collide with your real customers.

Extra information about the customer

Any other keys are kept as custom fields on the customer's profile: a plan name, an account number, a link to them in your admin. For example:

{
  "email": "jane@example.com",
  "name": "Jane Doe",
  "unique_id": "42",
  "plan": "Business",
  "admin": "https://app.example.com/admin/users/42",
  "expires": "2026-10-09T12:05:00Z"
}

When the customer starts a discussion, your support staff see these fields in a Private information (visible only to supporters) box on the discussion. Values that are web addresses become links. Customers never see them.

Encrypting it

The multipass is encrypted with AES so that only Tender can read it, and no one can make one without your SSO API key:

  1. Key: take the SHA-1 digest of your SSO API key followed by your Site key (SHA1(sso_api_key + site_key), as raw bytes) and keep the first 16 bytes.
  2. Encrypt the JSON with AES-128 in CBC mode, with that key, an initialization vector of 16 zero bytes, and PKCS#7 padding (the default in most libraries).
  3. Encode the result in URL-safe Base64: - instead of +, _ instead of /, and no = at the end.

The result can go in a URL as it is.

Ruby

require 'openssl'
require 'base64'
require 'json'
require 'time'

SITE_KEY = 'yoursite'                 # your Site key
SSO_KEY  = ENV.fetch('TENDER_SSO_KEY') # your SSO API key

def tender_multipass(data)
  cipher = OpenSSL::Cipher.new('aes-128-cbc')
  cipher.encrypt
  cipher.key = OpenSSL::Digest::SHA1.digest(SSO_KEY + SITE_KEY)[0, 16]
  cipher.iv  = "\0" * 16
  encrypted  = cipher.update(data.to_json) + cipher.final
  Base64.urlsafe_encode64(encrypted).delete('=')
end

token = tender_multipass(
  email:     'jane@example.com',
  name:      'Jane Doe',
  unique_id: '42',
  expires:   (Time.now.utc + 300).iso8601
)
puts "https://yoursite.tenderapp.com/?sso=#{token}"

PHP

<?php
$site_key = 'yoursite';                 // your Site key
$sso_key  = getenv('TENDER_SSO_KEY');   // your SSO API key

function tender_multipass($data, $site_key, $sso_key) {
    $key = substr(sha1($sso_key . $site_key, true), 0, 16);
    $iv  = str_repeat("\0", 16);
    $encrypted = openssl_encrypt(json_encode($data), 'aes-128-cbc', $key, OPENSSL_RAW_DATA, $iv);
    return rtrim(strtr(base64_encode($encrypted), '+/', '-_'), '=');
}

$token = tender_multipass([
    'email'     => 'jane@example.com',
    'name'      => 'Jane Doe',
    'unique_id' => '42',
    'expires'   => gmdate('c', time() + 300),
], $site_key, $sso_key);
echo "https://yoursite.tenderapp.com/?sso=" . $token . "\n";

Node.js

const crypto = require('crypto');

const SITE_KEY = 'yoursite';                 // your Site key
const SSO_KEY = process.env.TENDER_SSO_KEY;  // your SSO API key

function tenderMultipass(data) {
  const key = crypto.createHash('sha1').update(SSO_KEY + SITE_KEY).digest().subarray(0, 16);
  const cipher = crypto.createCipheriv('aes-128-cbc', key, Buffer.alloc(16));
  const encrypted = Buffer.concat([cipher.update(JSON.stringify(data)), cipher.final()]);
  return encrypted.toString('base64url');
}

const token = tenderMultipass({
  email: 'jane@example.com',
  name: 'Jane Doe',
  unique_id: '42',
  expires: new Date(Date.now() + 5 * 60 * 1000).toISOString(),
});
console.log(`https://yoursite.tenderapp.com/?sso=${token}`);

Checking a multipass

Once single sign-on is on, SSO Debugger appears in the Extras sidebar (the SSO token debug tool link on the Single Sign-On page goes there too). Paste a multipass under Debug a MultiPass Token and click Decode token to see what Tender reads from it, or why it can't.

The usual problems:

  • "The MultiPass token has expired." expires is missing or in the past. Check your server's clock and that the time is in UTC.
  • "The MultiPass token was not able to be decrypted." The key is wrong (check the SSO API key and Site key, and their order), or the multipass was changed on the way, for example by escaping it twice.
  • "The decrypted MultiPass token is not valid JSON." The data you encrypted isn't a JSON object.

The support widget

The support widget on your own website takes a multipass too, in its sso option, so customers using it are logged in.

Before multipasses, Tender could log people in from cookies your app sets, when Tender runs on a subdomain of your app's domain (your app at example.com, Tender at help.example.com). It still works, but a multipass is simpler and safer; use it for anything new.

Your app sets these cookies on .example.com when someone logs in:

Cookie
tender_email Their email address
tender_expires When the login expires, in seconds since 1970 (1893456000)
tender_name Their name (optional)
tender_hash The HMAC-SHA1 (hex) of host/email/expires, or host/email/expires/name with a name, made with your SSO API key (single sign-on must be on)
tender_<anything> Extra information, shown like a multipass's extra keys

host is your site's custom domain (help.example.com) or its yoursite.tenderapp.com address. To check your code: with the key monkey, the string help.example.com/jane@example.com/1893456000 gives 4b3a6af4b05feb08183c4aa81b818557961bae3b.

Google Sign-In

The same page can also let people log in to Tender with their Google account. Create an OAuth 2.0 client ID in the Google Cloud console, add the addresses the page lists as authorized JavaScript origins, and paste the client ID into OAuth Client ID under Google Sign-In.

More from the knowledge base