This flow is for partners who need a trusted mapping between an AGG user.id and their own
internal user ID for rewards, analytics, or reconciliation. The assertion must come from your
backend, not from the browser.
How it works
Generate the app secret
Generate or rotate the app secret from the AGG admin dashboard, then store it in your backend
secrets manager. Never expose it to the browser.
Sign the assertion on your backend
Build an HMAC over {externalId}:{timestamp} using the app secret. This proves the assertion
came from your backend.
Send the assertion to the frontend
Return { externalId, timestamp, hmac } from your own API after the user is authenticated in
your app.
Link it in AGG
Call client.linkExternalId(assertion) or the useExternalId() hook. AGG returns the updated
UserProfile with externalId populated.
Examples
Backend signing
import { signExternalId } from "@agg-market/sdk/server";
// Example: partner user record from your own database/session
const externalId = currentPartnerUser.id;
const assertion = signExternalId(process.env.AGG_APP_SECRET!, externalId);
// Return this from your backend to your frontend
return assertion;
import hashlib
import hmac
import time
external_id = current_partner_user["id"]
timestamp = int(time.time() * 1000)
payload = f"{external_id}:{timestamp}".encode()
digest = hmac.new(
bytes.fromhex(AGG_APP_SECRET),
payload,
hashlib.sha256,
).hexdigest()
assertion = {
"externalId": external_id,
"timestamp": timestamp,
"hmac": digest,
}
Frontend linking
import { createAggClient } from "@agg-market/sdk";
const client = createAggClient({
baseUrl: "https://api.agg.market",
appId: "your-app-id",
});
// assertion comes from your backend
const profile = await client.linkExternalId(assertion);
console.log(profile.externalId);
// "partner-user-123"
import { useEffect, useRef } from "react";
import { useExternalId } from "@agg-market/hooks";
function LinkPartnerAccount({
assertion,
}: {
assertion: { externalId: string; timestamp: number; hmac: string } | null;
}) {
const { linkExternalId } = useExternalId();
const lastLinkedAssertion = useRef<string | null>(null);
useEffect(() => {
if (!assertion) return;
const key = `${assertion.externalId}:${assertion.timestamp}`;
if (lastLinkedAssertion.current === key) return;
lastLinkedAssertion.current = key;
void linkExternalId(assertion).catch(() => {
lastLinkedAssertion.current = null;
});
}, [assertion, linkExternalId]);
return null;
}
Once linked, externalId is returned on the updated UserProfile and on future
client.getCurrentUser() calls.