Logo

Authentication

Path-based referral link and the HMAC-SHA256 signing contract (optional SSO).

Every Shop session begins with a path-based referral link. Bluecom issues you a provider slug; you open that link inside an iframe, WebView, or Telegram Mini App. User identity (SSO) is optional and is added via a short-lived HMAC-SHA256 signature on the URL.

/<slug>[/<sale_channel>][?uid=<userId>&ts=<unix>&sign=<hmac>][&lang=vi|en]
ComponentLocationRequiredDescription
slugPath segment #1YesYour provider slug, issued by Bluecom. Replaces the old ?partnerCode=.
sale_channelPath segment #2NoPins a sale channel. Omit → default channel. The channel must be linked + active and carry a payment method.
uidQueryNo¹Stable identifier of the user in your system — the link key to their Shop account.
tsQueryNo¹Unix epoch in seconds (not milliseconds). A positive integer.
signQueryNo¹hex(HMAC-SHA256(partnerSecret, "${uid}:${ts}")). Lowercase hex.
langQueryNovi (default) or en. Overrides locale.

¹ The uid + ts + sign trio travels together — all of it or none. No trio → a guest session (unauthenticated, still bound to the right channel). A sign present but missing uid/ts is treated as a tampered link and returns INVALID_LINK.

Signing contract

When you want to pre-link a user account (SSO), your backend signs the identity trio:

  • The signed string is exactly uid:ts — colon-separated, no spaces, no JSON.
  • slug is not part of the signed string — it only selects which partnerSecret to verify against.
  • sign is the lowercase hex of HMAC-SHA256.

Validation rules

  • ts must be within ±5 minutes of server time, else the link is rejected.
  • sign is compared in constant time.
  • slug must resolve to an active provider, else NO_PARTNER.
  • sale_channel (if present) must be linked + active for the provider; otherwise the mint is rejected and the Shop does not fall back to a default channel.

Signed vs guest

Whether a signature is required depends on the surface (see Embedding):

SurfaceSignatureIdentity
iframeUnsignedEnters as a guest; the user signs in inside the Shop if needed.
Native WebViewSignedHMAC trio required — missing/invalid is a terminal error.
Telegram Mini AppProvider credentialUses Telegram initData, not HMAC.
KBZPay In-App H5Provider credentialUses kbzpay_token, not HMAC.

Security rules

  1. partnerSecret MUST live only on your backend. Never embed it in app binaries, web bundles, or repo code.
  2. Mint sign immediately before opening the link. The 5-minute window is short by design.
  3. uid must be stable per end user. Changing it creates a new Shop account.
  4. HTTPS end-to-end. Plain HTTP links are rejected in production.

Not signing yourself? Use the Hub

If you don't run a signing backend, the Bluecom team can generate a referral link in the Hub (including a signed link for WebView). For iframe you only need an unsigned link — no partnerSecret required.

Code samples

The samples below build a signed link (for WebView / SSO). For iframe, drop the entire uid/ts/sign query.

Node.js

import crypto from "node:crypto";

const SLUG = "acme-bank";            // issued by Bluecom
const SALE_CHANNEL = "acme-default"; // optional: pin a sale channel
const PARTNER_SECRET = process.env.BLUECOM_PARTNER_SECRET!; // server-only

export function buildShopUrl(userId: string): string {
  const ts = Math.floor(Date.now() / 1000);
  const sign = crypto
    .createHmac("sha256", PARTNER_SECRET)
    .update(`${userId}:${ts}`)
    .digest("hex");

  const params = new URLSearchParams({ uid: userId, ts: String(ts), sign });
  return `https://<shop-host>/${SLUG}/${SALE_CHANNEL}?${params.toString()}`;
}

C# (.NET 8+)

using System.Security.Cryptography;
using System.Text;
using System.Web;

public static class BluecomShopUrlBuilder
{
    private const string Slug = "acme-bank";
    private const string SaleChannel = "acme-default";
    private static readonly string PartnerSecret =
        Environment.GetEnvironmentVariable("BLUECOM_PARTNER_SECRET")!;

    public static string Build(string userId)
    {
        var ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
        var message = $"{userId}:{ts}";

        using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(PartnerSecret));
        var sign = Convert.ToHexString(hmac.ComputeHash(Encoding.UTF8.GetBytes(message)))
            .ToLowerInvariant();

        var qs = HttpUtility.ParseQueryString(string.Empty);
        qs["uid"] = userId;
        qs["ts"] = ts.ToString();
        qs["sign"] = sign;

        return $"https://<shop-host>/{Slug}/{SaleChannel}?{qs}";
    }
}

Error responses

NO_PARTNER (slug not found), INVALID_LINK (bad/expired signature or invalid channel), VERIFICATION_FAILED (identity sign-in failed). See Reference › Error codes.

On this page