Partner External ID Linking
Link an authenticated AGG user to your app's internal user ID with an HMAC assertion
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 or rotate the app secret from the AGG admin dashboard, then store it in your backend secrets manager. Never expose it to the browser.
Build an HMAC over {externalId}:{timestamp} using the app secret. This proves the assertion
came from your backend.
Return { externalId, timestamp, hmac } from your own API after the user is authenticated in
your app.
Call client.linkExternalId(assertion) or the useExternalId() hook. AGG returns the updated
UserProfile with externalId populated.
Webhook-assisted linking
If your backend needs to connect new AGG users to existing partner users, subscribe to
accounts.created. The event includes the AGG userId and, when available from magic-link or
OAuth sign-in, email.
Use that email to resolve your internal user record, then complete the normal signed assertion flow
for that authenticated user. After client.linkExternalId(assertion) succeeds, AGG emits
accounts.linked with the AGG userId and your externalId.
import { parseWebhookEvent } from "@agg-build/sdk/server";
const event = parseWebhookEvent(rawBody, req.headers, process.env.AGG_WEBHOOK_SECRET!);
if (event.type === "accounts.created" && event.data.email) {
const partnerUser = await users.findByEmail(event.data.email);
if (partnerUser) {
await pendingLinks.store({
aggUserId: event.data.userId,
externalId: partnerUser.id,
});
}
}
accounts.created.data.email is null when AGG does not have an email for the principal, such
as wallet-only sign-in or OAuth providers that do not return email.
Examples
Backend signing
import { signExternalId } from "@agg-build/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;Frontend linking
import { createAggClient } from "@agg-build/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"Once linked, externalId is returned on the updated UserProfile and on future
client.getCurrentUser() calls.