Auth Protection

Prevent fake signups and account takeover with a blended IP, email, and browser-reputation verdict plus multi-account correlation on every signup and login.

One server-to-server call returns a blended IP, email, and browser-reputation verdict — plus multi-account correlation — for any signup or login. Drop the beacon on your auth pages, resolve the visitor from your backend, then flag, gate, or block on the verdict.

Your auth provider’s user.created webhook carries no IP, no user agent, and no browser context, so by the time a fake account or a takeover attempt reaches your backend the signals that would have caught it are already gone. Disposable emails, datacenter IPs, and one person spinning up dozens of accounts all look identical at the point you can actually block them. Auth Protection scores the visitor at the edge before the form is submitted, so the verdict is ready the moment your server creates the account.

When to use it

Reach for Auth Protection wherever an account is created or a session is established and you want to catch abuse at the point you can still block it — signup, login, password reset, or a step-up flow. A datacenter or residential-proxy IP on a consumer signup, a disposable email, or twenty accounts sharing one browser fingerprint are all invisible per-request but obvious here.

It complements the beacon and server reporting, which score full requests into your dashboard. Auth Protection is the synchronous, secret-key lookup you call from your backend at the auth decision point — and because the verdict only ever crosses back to a secret-key call, it is never exposed to the browser and cannot be tampered with.

How it works

  1. Drop the beacon on your auth pages

    Add the FormShield beacon to your signup and login views. It sets a first-party _fs cookie and scores the visitor at the edge — IP reputation, email signals, browser fingerprint, automation tells — before the form is ever submitted, so the verdict is ready when your server needs it.

  2. Resolve the visitor from your backend

    On signup or login, read the _fs cookie server-side and call POST /v1/sessions/resolve with a secret key. It returns the edge verdict, session continuity (fresh, history-less sessions are themselves a tell), and multi-account correlation, then binds the account id you pass so future lookups stay linked even after the cookie is cleared.

  3. Flag, gate, or block on the verdict

    Use the returned decision and the count of accounts sharing a fingerprint or IP to flag a signup for review, step up verification, or reject it. Because the verdict only ever returns to a secret-key backend call, it is never exposed to the browser and cannot be tampered with.

Quickstart

Read the _fs cookie server-side and send it, along with the visitor’s IP and the email and account id you’re creating, to POST /v1/sessions/resolve with your secret key (sessions scope). The beacon on your auth page must have already scored the visitor for a verdict to be ready.

bash
curl -X POST https://api.formshield.dev/v1/sessions/resolve \
  -H "Authorization: Bearer fs_live_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "<_fs cookie read server-side>",
    "ip": "203.0.113.42",
    "email": "user@example.com",
    "external_user_id": "user_2abc123",
    "observation_type": "auth.signup"
  }'

The response carries the blended verdict, session continuity, multi-account correlation, and bound: true once the account id is linked:

json
{
  "version": "1",
  "data": {
    "bound": true,
    "verdict": { "score": 0.82, "decision": "review", "reasons": ["datacenter_ip", "shared_fingerprint"] },
    "continuity": { "found": true, "first_seen": 1733500000000, "last_seen": 1733500120000, "age_seconds": 120, "observation_count": 3, "is_fresh": false },
    "correlation": { "accounts_sharing_session": 1, "accounts_sharing_fingerprint": 7, "accounts_sharing_ip": 4, "linked_emails": 6 }
  },
  "error": null,
  "metadata": {
    "request_id": "req_a1b2c3d4e5f6",
    "processing_time_ms": 38
  }
}

This response says: the visitor came from a datacenter IP and shares a browser fingerprint with six other accounts, so the blended verdict is review. Seven accounts share this fingerprint and four share the IP — the core fake-signup tell. Branch on verdict.decision and the correlation counts to decide whether to allow, step up, or reject the account.

The signals

Each call fuses four independent signals. No single tell decides the outcome — the blended verdict and the correlation counts are read together.

Blended reputation verdict

A single decision — allow, review, or block — fused from IP class (datacenter, VPN, proxy, Tor, residential proxy), email reputation, and browser fingerprint, with the reasons that drove it. The verdict crosses back only on a secret-key call, never to the browser.

Multi-account correlation

Counts of distinct identities that share this visitor’s fingerprint, IP, or session. One person registering twenty accounts is invisible per-request but obvious here. This is the core fake-signup tell.

Session continuity

First-seen, last-seen, age, and an is_fresh flag. A brand-new, history-less session arriving straight at your signup form is weak but useful corroborating evidence of automation.

Durable identity binding

Pass external_user_id (e.g. a Clerk or Auth0 user id) and FormShield binds it to the visitor and persists the link in ClickHouse. Correlation survives a cleared cookie because the durable join is fingerprint plus IP, not the cookie alone.

The fields

The data payload groups the verdict, the continuity history, and the correlation counts. Branch on verdict.decision and the correlation counts together.

bound boolean

Whether the external_user_id you passed was bound to this visitor. Once true, future lookups for the same identity stay linked through fingerprint and IP even after the _fs cookie is cleared.

verdict object

The blended decision: score (0.01.0), decision (allow | review | block), and reasons — the tells that fired, e.g. datacenter_ip, shared_fingerprint. Fused from IP class, email reputation, and browser fingerprint.

continuity object

Session history: found, first_seen, last_seen, age_seconds, observation_count, and is_fresh. A fresh, history-less session arriving straight at signup is weak but useful corroborating evidence of automation.

correlation object

Multi-account linkage: accounts_sharing_session, accounts_sharing_fingerprint, accounts_sharing_ip, and linked_emails. High counts on fingerprint or IP are the core fake-signup tell — one person spinning up many accounts.

request_id string

Identifier for the stored observation, prefixed req_. Correlates this resolve with its observation in the dashboard.

Endpoints

POST /v1/sessions/resolve endpoint path

Live. Read the _fs cookie server-side and resolve the visitor: returns the blended verdict, session continuity, and multi-account correlation, and binds the external_user_id you pass. Secret key, sessions scope. A raw session resolve is 2 credits.

POST /v1/auth/check endpoint path

Coming soon. A higher-level pre-flight that wraps the same IP, email, browser, continuity, and correlation signals into a single allow / review / block call for a signup or login decision. Until it ships, call /v1/sessions/resolve and branch on its verdict.

Common questions

How do I prevent fake signups with FormShield today?

Add the beacon to your signup page, then call POST /v1/sessions/resolve from your backend (secret key, sessions scope) when an account is created. The response gives you a blended IP/email/browser verdict plus a count of other accounts sharing the same fingerprint or IP, so you can flag, step up, or reject. This endpoint is live now. A higher-level POST /v1/auth/check pre-flight that wraps the same signals into a single allow/review/block call is coming soon.

Do I have to store risk data in my own database?

No. You pass your account id as external_user_id at signup and FormShield keeps the binding and history. To render risk later, call GET /v1/users/{external_user_id} for that identity’s current verdict, first/last seen, and multi-account linkage. The customer stores nothing; FormShield owns the identity-risk state.

What does this cost in credits?

Credits are weighted per operation: a signup check is 5 credits, a login check is 1 credit, and a raw session resolve is 2 credits. You meter and bill in credits rather than raw request counts, so heavier auth decisions cost proportionally more than a simple login.

Next steps

Type to search…

↑↓ navigate open esc close