AbuseGraph + Clerk
Check Clerk signup and login webhooks with the HTTPS API and optional browser signals.
Quick path
- Add
sk_test_…,pk_test_…, andABUSEGRAPH_SITEto env. - Collect browser signals and send
toCheckBodyto your server before starting signup/sign-in. - Call your backend before Clerk signup/sign-in to enforce the result; use webhooks for audit notifications.
Keys
| Key | Env | Use |
|---|---|---|
| Secret | ABUSEGRAPH_SECRET_KEY (sk_test_… / sk_live_…) | Server /api/v1/check |
| Publishable | NEXT_PUBLIC_ABUSEGRAPH_PUBLISHABLE_KEY (pk_test_…) | Browser SDK |
| Site | ABUSEGRAPH_SITE | DNS-verified domain |
Free includes 1,000 live API checks / month after DNS verify. Test keys never bill.
Env
ABUSEGRAPH_SITE=yourdomain.com
ABUSEGRAPH_CHECK_URL=https://abusegraph.com/api/v1/check
ABUSEGRAPH_SECRET_KEY=sk_test_…
ABUSEGRAPH_SECRET_KEY_TEST=sk_test_…
NEXT_PUBLIC_ABUSEGRAPH_PUBLISHABLE_KEY=pk_test_…Use sk_live_… / pk_live_… in production after DNS verify.
Server check
Call the HTTPS API from your server. Keep ABUSEGRAPH_SECRET_KEY in server-only environment configuration. Events: signup | login | password_reset | email_change; sessionId is optional.
const API = "https://abusegraph.com/api/v1/check";
export async function scoreAuth(input: Record<string, unknown>) {
const site = process.env.ABUSEGRAPH_SITE!;
const response = await fetch(API, {
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": process.env.ABUSEGRAPH_SECRET_KEY!,
"x-abusegraph-site": site,
},
body: JSON.stringify({
...input,
event: typeof input.event === "string" ? input.event : "signup",
site,
}),
});
if (!response.ok) throw new Error(`AbuseGraph check failed: ${response.status}`);
return response.json();
}Run this before creating an account or issuing a session. Handle block and challenge according to your policy; 402 means the live monthly allowance is exhausted.
Browser signals (recommended)
Load the browser SDK from the AbuseGraph CDN before your signup/login code. The publishable key is safe to expose; send the resulting body to your own backend, which makes the authoritative check with its server-held secret key.
<script src="https://abusegraph.com/sdk/abusegraph.min.js"></script>
<script>
const sdk = AbuseGraph.init({ publicKey: "pk_test_…" });
async function collectForAuth(email, event = "signup") {
const collected = await sdk.collect();
const evaluated = await sdk.evaluate(collected, { email });
return sdk.toCheckBody(collected, {
email,
event,
verdictToken: evaluated.verdictToken?.token,
});
}
</script>POST the returned JSON to your own endpoint. Never treat the browser result as the authoritative decision or put an sk_ key in browser code.
Clerk webhooks
user.created (signup audit)
This webhook runs after user creation, so it cannot prevent signup. Run the same check through your app's backend before calling Clerk's signup flow when enforcement is required.
export async function POST(req: Request) {
const evt = await req.json()
if (evt.type !== "user.created") return new Response("ok")
const email = evt.data.email_addresses?.[0]?.email_address
const browser = evt.data.unsafe_metadata?.abusegraph ?? {}
const result = await scoreAuth({
...browser,
email,
userId: evt.data.id,
event: "signup",
ip: req.headers.get("x-forwarded-for") ?? undefined,
})
if (result.verdict === "block") {
// Notify your review workflow; this webhook is post-creation.
}
return Response.json(result)
}session.created (login audit)
This webhook runs after a session is created. Check through your backend before completing sign-in when the verdict must gate access.
if (evt.type === "session.created") {
const email = evt.data.user?.email_addresses?.[0]?.email_address
const result = await scoreAuth({
email,
userId: evt.data.user_id,
event: "login",
ip: req.headers.get("x-forwarded-for") ?? undefined,
})
if (result.verdict === "block") {
// Revoke session / ban user
}
}Lifecycle events
- login —
session.createdwebhook withevent: "login". - password_reset — call check from your reset handler or a custom webhook with
event: "password_reset". - email_change — check before applying the Clerk email update with
event: "email_change".
Platform
Lists, rules, and linked accounts apply on every check — configure in the console. Optional session: POST /api/v1/session. Native apps: iOS, Android, React Native.
Verify
Call your server gate before signup/sign-in with a test key; confirm allowed checks in Activity and ensure blocked requests never create an account/session. Webhook notifications are post-event audit only.