Single Sign-On
The Pubble Single sign-on (SSO) solution allows you (the site owner) to easily build an internal communications platform among site admins and internal users. Once users are authenticated on your website, they do not need to sign-in again on Pubble. To enable this, you need to include existing "user details message" in our widget code (see below for details). The Pubble system will collect the user data from your side and will use it to update the users profile on Pubble, and will also provide your internal users with a seamless authenticated session on Pubble.
For SSO Pubble uses a technology called JSON Web Token (JWT) for securely exchanging authenticated user data between your system and Pubble
SSO functionality is currently available for the Live QA, Live Blog and Community QA apps
User sign-in flow
Note: At this stage, we presume user has already signed in on your system, and your system is able to feed enough user info in step 1.
Add SSO Key
Before you are able to create a secure JSON message and use SSO, you first need to add an SSO key to your Pubble account. This is the key that you will use to create a secure hash of the JSON message. This key will only be known to yourself and Pubble, it is important not to share it.
To add an SSO key go to the admin center and go to Community > Settings > Single Sign-On enter an alphnumeric value, something that cannot be easily guessed.
Choose the Hash Algorithm
You can also choose the hash algorithm you wish to use to generate the signature. To select the hash algorithm used go to the admin center and go to Community > Settings > Single Sign-On
You can select between HMAC SHA1 and HMAC SHA256, the latter is considered more secure and thus is the recommended one to use
Step 1: Generate JSON-serialized user data
This needs to include the user information that you will send to Pubble for creating/updating a users profile on Pubble.
The message body must include the following case sensitive properties unless noted otherwise:
{
"userID":"uniqueId_12345678923",
"email":"testsso@test.co",
"admin":"false",
"name":"pubblesso",
"avatar":"http://png-1.findicons.com/files/icons/1072/face_avatars/300/i04.png",
"userURL":"http://ssotest.com/",
"jobTitle":"CEO of Widgets Co.",
"emailNotification": "false"
}
Step 2: Timestamp (NOT Base-64 encoded)
Generate a long value timestamp when the JSON message was created. The timestamp value is current time in Unix-epoch milliseconds. If the timestamp is not current the SSO message may be rejected.
e.g. Java: long timestamp = System.currentTimeMillis();
e.g. PHP: $time = time();
Step 3: Generate Base-64 encoded user data
Generate a base64 encoded value of user JSON message which was created in step 1.
e.g. Java: String base64EncodedStr = Base64.encodeBase64(json);
Step 4: HMAC format signature
Next you need to generate a signature in the HMAC-SHA1 or HMAC-SHA256 format
The signature must be generated from the message of the following format. It is important to include the single space between the base64 encoded JSON message and the timestamp
HMAC->SHA256(pubble_sso_key, base64EncodedStr + ' ' + timestamp)
Note: base64EncodedStr was generated in step 3. The timestamp was generated in step 2.
Step 5: SSO Message
Once your signature has been generated you need to create an SSO Message which is composed of the three parts (base64EncodedStr, signature and timestamp) each separated with a single white space
Once created, it will look something like the following:
eyJ1c2VySUQiOiJ1bmlxdWVJZF8xMjM0NTY3ODkyMyIsImVtYWlsIjoidGVzdHNzb0B0ZXN0LmNvIiwiYWRtaW4iOiJmYWxzZSIsIm5hbWUiOiJwdWJibGUgc3NvIiwiYXZhdGFyIjoiaHR0cDovL3BuZy0xLmZpbmRpY29ucy5jb20vZmlsZXMvaWNvbnMvMTA3Mi9mYWNlX2F2YXRhcnMvMzAwL2kwNC5wbmciLCJ1c2VyVVJMIjoiaHR0cDovL3Nzb3Rlc3QuY29tLyJ9 3d8e70d6318af5bd1cab6580f7afdfe96b2a949d 1594057853438
Step 6: Add SSO message in widget code
Now you have the SSO message, you need to include it in the embedded Pubble widget code by adding it as the value for the following data attribute data-app-auth_info:
<div class="pubble-app PQAQ_section" data-app-id="12345" data-app-identifier="12345" data-app-auth_info="sso_message"></div>
<script type="text/javascript" src="https://cdn.pubble.io/javascript/loader.js" defer></script>
Java example code
Below is sample Java code to generate the SSO message
String PUBBLE_SSO_KEY = "Your_SSO_key";
// Step 1. User data, replace values with authenticated user data
HashMap<String, String> message = new HashMap<String, String>();
//your userid in your system
message.put("userID","uniqueId_12345678923");
message.put("name","test sso");
// User email address
message.put("email","testsso@pubble.co");
// User avatar URL (optional)
message.put("avatar","http://png-1.findicons.com/face_avatars/300/i04.png");
// User website or profile URL (optional)
message.put("userURL","http://test.com/");
message.put("admin", "false");
message.put("jobTitle", "CEO of Widgets co.");
// Step 2. Get the timestamp
long timestamp = System.currentTimeMillis();
// Step 3. Encode user data
ObjectMapper mapper = new ObjectMapper();
String jsonMessage = mapper.writeValueAsString(message);
String base64EncodedStr = new String(Base64.encodeBase64(jsonMessage.getBytes()));
// Step 4. Generate signature
String signature = "";
try {
signature = calculateRFC2104HMAC(base64EncodedStr + " " + timestamp, PUBBLE_SSO_KEY);
// Step 5. Print out the SSO message
System.out.println(base64EncodedStr + " " + signature + " " + timestamp);
} catch (Exception e) {
e.printStackTrace();
}
Node.js example code
Below is sample Javascript code to generate the SSO message
// Step 1. import crypto
var crypto = require('crypto');
// Step 2. User data, replace values with authenticated user data
var user = {
"userID":"uniqueId_12345678923",
"name":"test sso",
"email":"testsso@pubble.co",
"avatar":"http://png-1.findicons.com/face_avatars/300/i04.png",
"userURL":"http://test.com/",
"admin":"false",
"jobTitle":"CEO of Widgets co."
}
// Step 3. Get the timestamp
let timestamp = new Date().getTime();
// Step 4. Encode user data
let base64EncodedStr = nodeBase64.encode(JSON.stringify(user));
// Step 5. Generate signature
var signature = crypto.createHmac('SHA256', "YOUR_SSO_SECURITY_KEY").update(base64EncodedStr + ' ' + timestamp).digest('hex');
// Step 6. Generate SSO message token
var token = base64EncodedStr + ' ' + signature + ' ' + timestamp;
PHP example code
Below is sample PHP code to generate the SSO message
/**
* JSON ENCODE
* Checks if json_encode is not available and defines json_encode
* to use php_json_encode instead
*/
function cf_json_encode($data) {
return cfjson_encode($data);
}
function cfjson_encode_string($str) {
if(is_bool($str)) {
return $str ? 'true' : 'false';
}
return str_replace(
array('"', '/', "\n", "\r"),
array('\"', '\/', '\n', '\r'),
$str);
}
function cfjson_encode($arr) {
$json_str = '';
if (is_array($arr)) {
$pure_array = true;
$array_length = count($arr);
for ( $i = 0; $i < $array_length ; $i++) {
if (!isset($arr[$i])) {
$pure_array = false;
break;
}
}
if ($pure_array) {
$json_str = '[';
$temp = array();
for ($i=0; $i < $array_length; $i++) {
$temp[] = sprintf("%s", cfjson_encode($arr[$i]));
}
$json_str .= implode(',', $temp);
$json_str .="]";
}
else {
$json_str = '{';
$temp = array();
foreach ($arr as $key => $value) {
$temp[] = sprintf("\"%s\":%s", $key, cfjson_encode($value));
}
$json_str .= implode(',', $temp);
$json_str .= '}';
}
}
else if (is_object($arr)) {
$json_str = '{';
$temp = array();
foreach ($arr as $k => $v) {
$temp[] = '"'.$k.'":'.cfjson_encode($v);
}
$json_str .= implode(',', $temp);
$json_str .= '}';
}
else if (is_string($arr)) {
$json_str = '"'. cfjson_encode_string($arr) . '"';
}
else if (is_numeric($arr)) {
$json_str = $arr;
}
else if (is_bool($arr)) {
$json_str = $arr ? 'true' : 'false';
}
else {
$json_str = '"'. cfjson_encode_string($arr) . '"';
}
return $json_str;
}
}
/**
* JSON ENCODE
*/
/* pb_sso function is used to generate pubble sso information*/
function pb_sso() {
$key = "Your_key"; // your pubble SSO key
global $current_user;
get_currentuserinfo(); // Get current user data from your system.
if ($current_user->ID) {
$avatar_tag = get_avatar($current_user->ID);
$avatar_data = array();
preg_match('/(src)=((\'|")[^(\'|")]*(\'|"))/i', $avatar_tag, $avatar_data);
$avatar = str_replace(array('"', "'"), '', $avatar_data[2]);
if (current_user_can('manage_options')) {
$user_data = array(
'name' => $current_user->display_name,
'userID' => $current_user->ID,
'avatar' => $avatar,
'email' => $current_user->user_email,
'userURL' => $current_user->user_url,
'admin' => "false");
}
else {
// For normal user, no need to set admin field.
$user_data = array(
'name' => $current_user->display_name,
'userID' => $current_user->ID,
'avatar' => $avatar,
'email' => $current_user->user_email,
'userURL' => $current_user->user_url,
);
}
}
else {
$user_data = array();
}
// Get the timestamp
$time = time();
// Encode user data
$user_data = base64_encode(cf_json_encode($user_data));
// Encrypt user info with timestamp and pubble_key
$hmac = pb_hmacsha1($user_data.' '.$time, $key);
// Generate final SSO signature
$payload = $user_data.' '.$hmac.' '.$time;
return array('remote_auth_s2'=>$payload);
}
function pb_hmacsha1($data, $key) {
$blocksize=64;
$hashfunc='sha1';
if (strlen($key)>$blocksize)
$key=pack('H*', $hashfunc($key));
$key=str_pad($key,$blocksize,chr(0x00));
$ipad=str_repeat(chr(0x36),$blocksize);
$opad=str_repeat(chr(0x5c),$blocksize);
$hmac = pack(
'H*',$hashfunc(
($key^$opad).pack(
'H*',$hashfunc(
($key^$ipad).$data
)
)
)
);
return bin2hex($hmac);
}
Deleting an SSO user
You can delete an SSO user via a special endpoint. You need to encode the data the same way as above, however you only need to include the userID in the JSON construct. For example:
{
"userID":"uniqueId_12345678923"
}
The new SSO message then needs to be passed via the "authInfo" parameter of the following endpoint:
https://[subdomain].pubble.io/api/v2/sso/delete
| Parameter | Value | Example |
|---|---|---|
| authInfo | SSO Message | eyJ1c2VySUQiOiJ1bmlxdWVJZF8xMjM0NTY3ODkyMzc4NiJ9 bb389516df65ac80e590ba3f8dae63e594e3369a 1594060646029 |
Both GET and POST requests are supported.
Note: you must replace the subdomain with your own team subdomain on Pubble.
The response will be a JSON construct containing a response code and status message:
{
code: 200,
status: "ok"
}
The following response codes are possible:
| Status code | Outcome | Note |
|---|---|---|
| 200 | OK | Operation successful |
| 413 | Incorrect parameter value | Ensure the authInfo parameter is correct |
| 420 | Community not found | Check that the subdomain is correct |
| 421 | Account not found | The SSO account may have already been deleted, or the ID is incorrect |
| 434 | No key found | Check that an SSO secret key is defined for the community |
| 705 | Token invalid | Ensure the SSO Message data is correct or that secret key is the same |
| 706 | Timestamp invalid | Ensure the timestamp is present and correct |
| 500 | Server Error | Occurs if there is an issue deserializing JSON or calculating the HMAC token |
| 521 | Missing timestamp | Timestamp missing from SSO Message |
| 522 | Timestamp invalid | If the timestamp is not current it will be rejected. You must use a freshly generated timestamp. |