Edge
Back to Academy
Security 10 min read

Securing Login & Signup Flows

Credential stuffing and fake account waves are the two most common attacks on any site with a login form. Here's how to stop both without adding friction for the humans you actually want.

What you're actually defending against

Credential stuffing is the replay of username/password pairs leaked from other sites. Because people reuse passwords, a list that's 0.1% effective against your login form is still a profitable attack — and it looks like thousands of individually plausible login attempts, not one obvious flood.

Fake account creation feeds everything downstream: spam, referral fraud, free-tier abuse, review manipulation. By the time you notice it in your metrics, the accounts already exist and cleanup is expensive.

Both attacks share one property: they're automated. That's the property to test for at the door, before a single credential is checked or a single row is written.

1. Gate the form with Edge Shield

Add the Edge Shield widget to your login and signup forms, and verify the token server-side before your authentication logic runs. Tokens are single-use and expire after five minutes, so a bot can't harvest one token and replay it across a credential list.

// Login route: verify the Shield token before touching credentials
const res = await fetch('https://shield.edge.network/siteverify', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    secret: process.env.SHIELD_SECRET,
    response: req.body['edge-shield-response'],
    remoteip: req.ip,
  }),
})
const { success, score } = await res.json()

if (!success) return res.status(403).send('Verification failed')
if (score < 40) return requireEmailConfirmation() // step up, don't hard-block

// Only now check the password — bots never reach your auth logic
const user = await authenticate(req.body.email, req.body.password)

Two details matter here. First, pass remoteip — it lets Shield corroborate the client's network reputation. Second, the ordering: rejecting before authenticate() means stuffing attempts never touch your user table, which also keeps them out of your failed-login metrics and lockout logic.

If you haven't set up a widget yet, the Bot Protection with Edge Shield guide covers it end to end — it's two lines of markup and free forever.

2. Use the score to step up, not just block

Every verification returns a 1–100 humanity score. A hard pass/fail gate wastes that signal. For signups in particular, a graduated policy converts uncertain traffic instead of losing it:

Signal Signup policy
Score 70–100 Create the account normally.
Score 40–69 Create the account, but require email confirmation before first use.
Score 1–39 Reject, or hold for review. Watch for verified agents — they may be legitimate automation.

For logins, treat a low score on a correct password as its own signal — that's the signature of a stuffed credential that happens to be valid. Step up to email confirmation or 2FA rather than letting the session through, and you've turned a successful account takeover into a failed one.

3. Keep the boring layers too

Shield removes the bulk automation, but defence in depth still applies:

  • Rate-limit per account, not just per IP — stuffing attacks rotate IPs cheaply; five failed attempts against one account is a better tripwire than fifty from one address.
  • Return identical errors for "wrong password" and "no such user", on the same response timing, so the form can't be used to enumerate accounts.
  • Check passwords against known-breach lists at signup and password change — most stuffing lists are built from exactly those breaches.
  • Offer 2FA — it's the single strongest control against account takeover, and you should enable it on your own Edge account as well.