AbuseGraphDocs
Guides

AbuseGraph + Express

Express middleware with createCheckClient — score signup and login before issuing a session.

Quick path

  1. Set ABUSEGRAPH_SECRET_KEY and ABUSEGRAPH_SITE in env.
  2. Install @abusegraph/server (and @abusegraph/sdk if you have a browser client).
  3. Add middleware on register/login routes that calls createCheckClient.check.

Keys

KeyEnvUse
SecretABUSEGRAPH_SECRET_KEY (sk_test_… / sk_live_…)Server /api/v1/check
PublishableNEXT_PUBLIC_ABUSEGRAPH_PUBLISHABLE_KEY (pk_test_…)Browser SDK
SiteABUSEGRAPH_SITEDNS-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_… in production after DNS verify.

Server check

Use @abusegraph/server createCheckClient. Events: signup | login | password_reset | email_change. Optional sessionId.

import { createCheckClient } from "@abusegraph/server"

const abusegraph = createCheckClient({
  secretKey:
    process.env.NODE_ENV === "production"
      ? process.env.ABUSEGRAPH_SECRET_KEY! // sk_live_…
      : process.env.ABUSEGRAPH_SECRET_KEY_TEST ??
        process.env.ABUSEGRAPH_SECRET_KEY!, // sk_test_…
  site: process.env.ABUSEGRAPH_SITE!,
})

If you serve a web UI, use init + collect + evaluate + toCheckBody — NEVER bare sdk.check() alone as the authoritative decision. POST browserFields with your register/login request body.

Express middleware

import type { Request, Response, NextFunction } from "express"
import { createCheckClient } from "@abusegraph/server"

const abusegraph = createCheckClient({
  secretKey: process.env.ABUSEGRAPH_SECRET_KEY!,
  site: process.env.ABUSEGRAPH_SITE!,
})

export function abusegraphGuard(event: "signup" | "login") {
  return async (req: Request, res: Response, next: NextFunction) => {
    const email = req.body?.email
    if (!email) return next()

    const { password, ...browserFields } = req.body

    const result = await abusegraph.check({
      email,
      event,
      ip: req.ip,
      ...browserFields,
    })

    if (result.verdict === "block") {
      return res.status(403).json({ error: "blocked", ...result })
    }
    if (result.verdict === "challenge") {
      // require step-up before session create
    }

    res.locals.abusegraph = result
    next()
  }
}

app.post("/register", abusegraphGuard("signup"), createUserHandler)
app.post("/login", abusegraphGuard("login"), loginHandler)

Lifecycle events

  • loginabusegraphGuard("login") before session create.
  • password_reset — middleware or route handler with event: "password_reset".
  • email_change — call check after 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

POST to /register with sk_test_…, confirm Activity shows the check, and blocked emails get 403.