> ## Documentation Index
> Fetch the complete documentation index at: https://docs.suprsend.com/llms.txt
> Use this file to discover all available pages before exploring further.

# HMAC Authentication

> Steps to safely authenticate users and generate subscriber-id in headless Inbox implementation.

## 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](https://app.suprsend.com/en/production/vendors/inbox/suprsend-inbox). This key is unique to your workspace and should not be shared with anyone for security purposes

<CodeGroup>
  ```python python theme={"system"}
  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("=")
  ```

  ```go go theme={"system"}
  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))
  }
  ```

  ```javascript Node theme={"system"}
  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(/=+$/, "");
  }
  ```

  ```java java theme={"system"}
  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;
  	}
  }
  ```

  ```pgsql PL/pgSQL theme={"system"}
  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$;
  ```
</CodeGroup>

It is imperative that the inbox secret is stored safely on your server side and not exposed to client-side code.

<Warning>
  **NOTE:**

  The subscriber\_id must be generated by server-side code (not in browser)
</Warning>

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.

<Frame>
  <img src="https://mintcdn.com/suprsend/WdsZ2yuqLDH_ynbJ/images/subscriberslistingpage.png?fit=max&auto=format&n=WdsZ2yuqLDH_ynbJ&q=85&s=1910193999cffd3d0388977c8cb77fdc" width="2904" height="1724" data-path="images/subscriberslistingpage.png" />
</Frame>

***
