# Authentication

> Send your ZeroCaptcha API key in each format, read it from the environment, rotate it without an outage, and keep it out of code, logs and browsers.

Source: https://zerocaptcha.io/docs/authentication

Every call your code makes carries an API key. The key says which account the call is for and what
it may do. You create keys in the dashboard; see [API keys](https://zerocaptcha.io/docs/keys) for scopes, allowed
addresses, spend caps and revocation.

## Send the key

| Format | Where the key goes |
| --- | --- |
| REST v1 | `Authorization: Bearer zc_live_…` |
| [createTask format](https://zerocaptcha.io/docs/createtask) | `clientKey` in the JSON body |
| [2Captcha format](https://zerocaptcha.io/docs/2captcha) | the `key` parameter |

The API is at `https://api.zerocaptcha.io`. Read the key and the address from your environment, never from your
source code. The samples in these docs use `ZEROCAPTCHA_KEY` and `ZEROCAPTCHA_API`:

**curl**

```sh
export ZEROCAPTCHA_KEY="$(cat /run/secrets/zerocaptcha_key)"   # or from your secret manager
curl "$ZEROCAPTCHA_API/v1/balance" -H "Authorization: Bearer $ZEROCAPTCHA_KEY"
```

**Node**

```js
const key = process.env.ZEROCAPTCHA_KEY;
if (!key) throw new Error("Set ZEROCAPTCHA_KEY");

const response = await fetch(`${process.env.ZEROCAPTCHA_API}/v1/balance`, {
  headers: { Authorization: `Bearer ${key}` },
});
console.log(response.status, await response.json());
```

**Python**

```python
import os

import requests

key = os.environ["ZEROCAPTCHA_KEY"]
response = requests.get(
    f"{os.environ['ZEROCAPTCHA_API']}/v1/balance",
    headers={"Authorization": f"Bearer {key}"},
    timeout=15,
)
print(response.status_code, response.json())
```

**Go**

```go
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, _ := http.NewRequest(http.MethodGet, os.Getenv("ZEROCAPTCHA_API")+"/v1/balance", nil)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("ZEROCAPTCHA_KEY"))
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.StatusCode, string(body))
}
```

A key needs no cookie and no CSRF token: those belong to the dashboard's own session. A key can
create and read tasks and read the balance; managing keys, billing and the team takes a signed-in
dashboard session, so a leaked key can never create another key.

## What a key looks like

A key is 41 characters: `zc_live_`, 27 random characters, then a 6-character checksum. The prefix
makes a leaked key easy to spot, and the checksum lets a secret scanner confirm a match without
calling us. There is one kind of key: every task it creates is real, and charged if it succeeds.

A wrong, mistyped or unknown key is refused with
[`unauthorized`](https://zerocaptcha.io/docs/reference/errors#unauthorized) (HTTP 401), or
[`ERROR_KEY_DOES_NOT_EXIST`](https://zerocaptcha.io/docs/reference/errors#ERROR_KEY_DOES_NOT_EXIST) in the createTask
format. A revoked key is refused with [`key_revoked`](https://zerocaptcha.io/docs/reference/errors#key_revoked).

## Rotate without an outage

1. On the dashboard's **API keys** page, choose **Rotate** on the key and an overlap: 1 hour,
   24 hours or 7 days. The new key is shown once; copy it into your secret store.
2. Deploy it. During the overlap both keys work.
3. When every service uses the new key, end the overlap, or let it run out. The old key then
   answers `key_revoked`.

Rotate on a schedule, when someone who had the key leaves, and at once if it may have leaked.
[API keys](https://zerocaptcha.io/docs/keys#rotate-a-key) has the details.

## Key hygiene

- **Keep keys in a secret store** or the environment, never in source code, a repository, a
  container image, a screenshot or a support message. Support never needs your key.
- **Never send a key to a browser.** Call ZeroCaptcha from your server, and hand the browser only
  the result it needs. A key in front-end code or a mobile app can be read by anyone.
- **Never log it.** Leave the `Authorization` header out of request logs and error reports.
- **Use one key per service or environment,** named in the dashboard, so you can rotate or revoke
  one without touching the others, and see which one made a task.
- **Give each key only what it needs.** A reporting job needs only the `balance` scope.
- **Hold a key to your servers' addresses** with its IP allowlist, so a leaked key is useless
  elsewhere.
- **Cap a key's daily spend,** so a runaway loop or a leak costs at most the cap.
- **Watch it.** The keys page shows when each key was last used and from where.

If a key leaks, revoke it on the keys page: it stops at once, and tasks it already created run to
their end. Then create a new one.
