For React/Web apps, use JWT authentication instead. The @suprsend/react (drop-in) and @suprsend/react-core / @suprsend/web-sdk (headless) SDKs authenticate users with signed JWTs — see the client authentication guide and the React migration guide.This page documents the legacy HMAC subscriber_id flow that is still used by the React Native (@suprsend/react-headless) and Flutter Inbox SDKs. Do not use this for new React/Web integrations.
Why HMAC authentication is required?
When you initialize SuprSend’s Inbox on your website, you provide your SuprSend workspace API Key and a user’s distinct id. A savvy user can obtain this API Key with this setup and can initialize the inbox on their website with your API Key but with a different distinct id and start viewing that user’s notifications.
With HMAC authentication, an SHA-256 HMAC string (subscriber_id) is generated for each distinct_id and prevents unauthorized access to Inbox service by just spoofing distinct_id.
How to generate subscriber_id?
Use the below function in your server-side code to generate a unique unguessable subscriber_id using your distinct_id and inbox-secret (picked from the Inbox Vendor Integration page).
-
subscriber_id is unique to each distinct_id and should be generated for each user.
-
Inbox Secret is the
Shared Secret key available in your Inbox vendor page. This key is unique to your workspace and should not be shared with anyone for security purposes
import base64
import hashlib
import hmac
def hmac_rawurlsafe_base64_string(distinct_id: str, secret: str):
digest = hmac.HMAC(secret.encode(), msg=distinct_id.encode(), digestmod=hashlib.sha256).digest()
encoded = base64.urlsafe_b64encode(digest).decode()
return encoded.rstrip("=")
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
)
func HmacRawURLSafeBase64String(message, secret string) string {
hash := hmac.New(sha256.New, []byte(secret))
hash.Write([]byte(message))
return base64.RawURLEncoding.EncodeToString(hash.Sum(nil))
}
import crypto from "crypto";
// node versions >= v15.7.0, v14.18.0
function hmac_rawurlsafe_base64_string(distinct_id, secret) {
const hash = crypto
.createHmac("sha256", secret)
.update(distinct_id)
.digest("base64url");
return hash.replace(/=+$/, "");
}
// node versions < v15.7.0, v14.18.0
function hmac_rawurlsafe_base64_string(distinct_id, secret) {
return crypto
.createHmac("sha256", secret)
.update(distinct_id)
.digest("base64")
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
}
package test;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class TestHmacGeneratation {
public static void main(String[] args) throws Exception {
String distinct_id = "b8278572-2929-4af6-be2b-cdc2bc1f6256";
String secret = "IG-J8Wvf7M-w4ll13h53NJAMQQNHdUqFTSJ2JVAZl0s";
TestHmacGeneratation instance = new TestHmacGeneratation();
String output = instance.hmacRawURLSafeBase64String(distinct_id, secret);
System.out.println(output);
// prints dHBWYF4oV190o4j-e3eYxB-SCkeHnoaiofe8EmGk9JQ
}
private String hmacRawURLSafeBase64String(String distinctId, String secret) throws InvalidKeyException, NoSuchAlgorithmException {
Mac sha256mac = getSha256macInstance(secret);
byte[] macData = sha256mac.doFinal(distinctId.getBytes(StandardCharsets.UTF_8));
String hmacString = Base64.getUrlEncoder().withoutPadding().encodeToString(macData);
return hmacString;
}
private Mac getSha256macInstance(String secret) throws NoSuchAlgorithmException, InvalidKeyException {
final byte[] secretBytes = secret.getBytes(StandardCharsets.UTF_8);
SecretKeySpec keySpec = new SecretKeySpec(secretBytes, "HmacSHA256");
Mac sha256mac;
try {
sha256mac = Mac.getInstance("HmacSHA256");
sha256mac.init(keySpec);
} catch (NoSuchAlgorithmException e) {
throw e;
} catch (InvalidKeyException e) {
throw e;
}
return sha256mac;
}
}
CREATE EXTENSION "pgcryto";
CREATE OR REPLACE FUNCTION hmac_rawurlsafe_base64_string(distinct_id VARCHAR, secret VARCHAR) RETURNS VARCHAR
LANGUAGE PLPGSQL AS $func$
DECLARE
hmac_string VARCHAR;
BEGIN
hmac_string = encode(hmac(distinct_id::TEXT, secret, 'SHA256'), 'base64');
hmac_string = replace(replace(hmac_string, '+', '-'), '/', '_');
hmac_string = RTRIM(hmac_string, '=');
RETURN hmac_string;
END;
$func$;
It is imperative that the inbox secret is stored safely on your server side and not exposed to client-side code.
NOTE:The subscriber_id must be generated by server-side code (not in browser)
Even after setting up the inbox, if you are not able to see notifications then cross-check if your subscriber_id mentioned is exactly correct by opening the user’s tab in the Suprsend dashboard.