# Keys and access control

> How connection keys are made and stored, and how expiry, IP allow-lists, rate limits, lockouts, the AI access switch and Secrets limit access.

Every request to your site must carry a valid connection key (or a sign-in token) and pass a series of checks before a tool runs. This page describes those checks.

## Connection keys

- **Format.** A key is a long random string that starts with `wpai_`, followed by 43 random letters and digits. It is generated on your site when you create a connection.
- **Shown once, stored as a hash.** PowerWP AI stores a SHA-256 hash of the key and its last four characters, so you can tell connections apart. It cannot show the key again.
- **Where it is sent.** Setup steps use the `X-WPAI-Token` header, because many hosts strip the `Authorization` header. `Authorization: Bearer` also works.
- **One entrance only.** A key is accepted on PowerWP AI's own endpoint. It cannot be replayed against the rest of the WordPress REST API, admin-ajax.php or wp-admin.
- **Acts as an administrator.** The connection works as the administrator who created it. If that user is deleted or loses the administrator role, requests are refused.
- **Signed-in apps** use short-lived tokens instead of a key. See [Sign-in for AI apps](/docs/concepts/sign-in/).
- **Management keys** are a separate kind of key. AI apps cannot use them, and connection keys cannot use the management side.

## Expiry

When you create a connection, you choose when it expires: 7 days, 30 days, 90 days (preselected), 1 year or never. An expired key stops working by itself, and its status shows **Expired**. Edit the connection to set a new expiry. Using an expired key is logged as a security event.

## IP allow-list

An IP allow-list limits a connection to the addresses you list. Leave it empty to allow any address. Enter one address or range per line:

| Entry | Meaning |
|---|---|
| `203.0.113.4` | One IPv4 address |
| `203.0.113.0/24` | An IPv4 range |
| `2001:db8::1` | One IPv6 address |
| `2001:db8::/32` | An IPv6 range |

Entries that are not valid addresses or ranges are rejected when you save. A request from any other address is refused with HTTP 403 and logged. **Add my IP** fills in your current address.

If your site is behind a proxy or CDN, every request seems to come from the proxy. Under **Settings › Connection security**, **Client IP source** chooses where PowerWP AI reads the address: `REMOTE_ADDR` (the default), `CF-Connecting-IP`, `X-Forwarded-For` or `X-Real-IP`. Pick a proxy header only if the site really is behind that proxy, because otherwise clients could fake their address.

## Rate limits and lockouts

Both are under **Settings › Connection security**.

- **Rate limit per key.** The default is 240 requests a minute for each connection, and you can set 10 to 5000. Requests above the limit get HTTP 429 until the next minute.
- **Lockout threshold and duration.** The default is 10 failed attempts from one IP address within 15 minutes, which locks that address out for 15 minutes. You can set 3 to 1000 attempts and 1 to 1440 minutes.

A failed attempt is a request with an unknown key or a revoked one. An expired key does not count, because it is a genuine key. A lockout stops failing attempts only. A valid key from the same address still works, so apps that share an address with others are not locked out by someone else's mistakes.

Lockouts are recorded in the activity log, and you can get an e-mail about them.

## Revoke

Choose **Revoke** next to a connection to end it immediately. This cannot be undone: create a new connection to give the app access again. A revoked key that is used again counts as a failed attempt and is logged.

## AI access switch and read-only mode

The **AI access** switch at the top of PowerWP AI refuses every AI app at once, with an HTTP 503 answer that says AI access is paused. The PowerWP AI screens keep working. If you cannot log in to wp-admin, add this line to wp-config.php:

```
define( 'WPAI_MCP_DISABLED', true );
```

**Read-only mode** (**Settings › General › Read-only mode**) limits every connection to reading, whatever its permissions.

See [AI access switch and read-only mode](/docs/safety/access-switch/).

## What the Secrets permission unlocks

Without the Secrets permission, passwords and keys are masked in wp-config.php and .env files, in option values, in database results, in REST reads and in ability results. With it, a connection can:

- read those values unmasked when it asks for them, for example `fs_read` with `reveal_secrets=true`;
- edit wp-config.php and .htaccess;
- let `http_request` reach internal addresses with `allow_private`. Cloud metadata addresses stay blocked.

The Developer preset leaves Secrets out. Give it only for one task and remove it afterwards. See [Permissions and presets](/docs/concepts/permissions/).

## Alerts and records

Failed authentications, lockouts, revoked or expired keys that were used, blocked IP addresses and new IP addresses are recorded in the activity log under the **security** channel. Under **Settings › Alerts** you can add an e-mail address and choose the events to hear about. PowerWP AI sends at most one e-mail per event type every 10 minutes.

If a firewall or security plugin blocks `/wp-json/wpai/v1/`, allow that path: the endpoint has its own authentication, rate limits, lockouts and IP allow-lists. See [Troubleshooting](/docs/help/troubleshooting/).

:::cards
- [Security model](/docs/security/) — All the layers at a glance.
- [Connections and keys](/docs/concepts/connections/) — Create, edit and revoke connections.
- [Activity log](/docs/safety/activity-log/) — Review what every connection did.
:::

Source: https://powerwp.ai/docs/security/access-control/
