---
title: Attack protection
description: What stands in front of your sign-up and sign-in endpoints, and the one part you choose.
---

Open **Attack protection** in the console to see what guards an environment.
Most of it is always on: it comes with the environment and cannot be weakened
by mistake. One switch, human verification, is yours.

## Always on

| Protection | What it does |
| --- | --- |
| Account lockout | 10 failed sign-ins lock the account for 15 minutes. |
| Rate limit | 1,000 requests per minute for a development environment, 6,000 for production. Each signed-in user is also limited to 120 requests per minute. |
| Origin lock | In production, your publishable key is accepted only from your verified domain, its subdomains and your registered callbacks. A copy of your key on someone else's page is refused. Callers that send no origin, such as native apps and scripts, are unaffected. |
| Passwords | Hashed with Argon2id. Never stored or logged in the clear. |

Development environments have no verified domain, so the origin lock does not
apply there.

## Human verification

A challenge on sign-up and sign-in, checked on our side. The rate limit counts
requests from one source; human verification asks the question a distributed
attack cannot answer.

- **Production** is challenged from the moment it exists.
- **Development** is not challenged by default, so your integration tests can
  sign users up without solving anything.

You can turn it on or off per environment. Changing it needs a developer,
admin or owner role.

> **Warning:**
> Turning human verification off in production means anyone holding your
> publishable key, which ships in your page, can create accounts and attempt
> sign-ins at scale. The rate limit still applies per source, but a distributed
> attempt looks like ordinary traffic.

## What your users see

- A locked account is told to wait and try again later. The lock lifts on its
  own.
- With human verification on, the sign-in components show a short challenge.
  Most people pass it without doing anything.
- A rate-limited request gets `429` with code `rate_limited`. See
  [Errors](/api/errors).

Every lockout and failed challenge is recorded in [Logs](/console/logs).
