Stop throwaway e-mail addresses and mass sign-ups before accounts are created, with a built-in check the SDKs solve for you. On for every project, no setup.
Every project refuses fake sign-ups before an account is created, without a CAPTCHA widget or keys. It is on by default and runs on your project's own server.
- Throwaway addresses. Sign-ups from known throwaway e-mail domains (mailinator.com and about 140 more of the most used) are refused.
- Sign-ups per IP address and per network. Above the limit, the client must solve a short built-in check; at six times the limit, sign-ups from that address are refused for a while.
- Scripted clients. Clients that do not look like a browser or an app (such as curl or python-requests without a StitchDB SDK) must solve the check.
- Your own lists. Block domains you never want (subdomains included), or always allow your own.
It covers e-mail and phone sign-ups and sign-in links or codes that would create a user. Signing in to an existing account is not affected, and requests with the service role key are never checked.
#The built-in check
The check is a small proof of work: the client finds a number whose SHA-256 hash matches a challenge, which a browser does in a fraction of a second while a bot that creates thousands of accounts pays for each one. It is signed by your project, works once and expires after five minutes.
You do not need to change your code. The JavaScript SDK (2.10.0 and later) and the hosted sign-in page solve it automatically and send the request again. Other clients get:
HTTP 400
{ "code": 400, "error_code": "captcha_required", "msg": "Complete the sign-up check: …",
"challenge": { "algorithm": "SHA-256", "challenge": "…", "salt": "…", "maxnumber": 50000, "signature": "…" } }To solve it yourself, find number from 0 to maxnumber where the hex SHA-256 of salt + number equals challenge, then repeat the request with stitchdb_captcha set to the base64 of the challenge object with number added. A fresh challenge is also at GET /auth/v1/challenge.
async function solve(ch) {
for (let n = 0; n <= ch.maxnumber; n++) {
const d = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(ch.salt + n))
const hex = [...new Uint8Array(d)].map((b) => b.toString(16).padStart(2, '0')).join('')
if (hex === ch.challenge) return btoa(JSON.stringify({ ...ch, number: n }))
}
}
// body: { email, password, stitchdb_captcha: await solve(error.challenge) }#Settings
Studio → Authentication → Settings → Fake sign-up protection:
| Setting | Default | What it does |
|---|---|---|
| Protect sign-ups | On | Turns all of the below on or off. |
| Refuse throwaway e-mail addresses | On | Error 400 email_address_invalid. |
| Sign-ups per IP address | 10 per hour | Above this the check is required; at six times it, 429 over_request_rate_limit. 0 = no limit. |
| Sign-ups per network | 60 per hour | The same for a whole /24 (IPv4) or /48 (IPv6) network. |
| Built-in check | When needed | When needed, on every sign-up, or never (limits and domains only). |
| Check scripted clients | On | Clients such as curl without a StitchDB SDK get the check. |
| Blocked domains / Always allowed domains | None | Up to 500 each. Blocked: 400 email_address_invalid. |
The card also shows how many sign-ups were let through, solved the check or were stopped in the last 24 hours, and the latest stopped attempts with the e-mail address partly hidden.