# Authentication | React AI Autocomplete Docs

> For the complete documentation index, see [llms.txt](https://ai-autocomplete.com/llms.txt). A markdown version of any page on this site is available by appending `.md` to its URL path — the homepage is at `/index.md`.

Authentication guide for integrating the AI Autocomplete SDK with React. Code examples, setup, and API reference.

Source: https://ai-autocomplete.com/docs/react/authentication

---

Two key types. Public keys plug straight into the SDK from the browser. Secret keys live on your server and mint short-lived access tokens that the SDK uses — recommended for production.

[Manage your keys](https://ai-autocomplete.com/account/keys)

## Choosing a mode

Public key mode is the fastest path: drop a public key into apiConfig and you're done. Secret key + access token mode is what we recommend for production — your server keeps the secret key, mints short-lived access tokens, and the SDK handles refresh transparently.

## Public key mode

Use a public key when calling the SDK directly from the browser. Public keys are scoped, rate-limited, and safe to ship in client-side bundles. This is the fastest path to a working integration.

**auth-public-key.tsx**

```tsx
<AIAutocomplete
  apiConfig={{
    // Public key (pk_v1_...) — safe to ship in client bundles
    apiKey: import.meta.env.VITE_MAGICX_PUBLIC_KEY,
    endpoint: "https://api.ai-autocomplete.com/api/suggest",
    headers: { "X-Tenant": "acme" },
  }}
  onSubmit={handleSubmit}
/>;
```

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `type` | `"apiKey"` | — | Optional discriminator. Default when omitted. |
| `apiKey` | `string` | — | The public key sent as a Bearer token in the Authorization header. |
| `endpoint` | `string` | `"https://api.ai-autocomplete.com/api/suggest"` | Optional — full URL of the suggest endpoint. Defaults to the hosted endpoint, so you only need this when self-hosting. |
| `headers` | `Record<string, string>` | — | Additional headers merged into every request. |

Security

Public keys are safe in client bundles, but for production we recommend the secret key + access token flow below — short-lived tokens limit blast radius if a credential leaks. Never put a secret key in client code.

## Secret key + access token (recommended)

Keep your secret key on your backend server. The server — never the browser — exchanges it for a short-lived access token. Your frontend fetches the token from your own backend route, then hands it to the SDK via getAccessToken. The SDK handles refresh, retries, and concurrency dedupe — the secret key never reaches the browser.

### On your server

On your backend, expose a route that exchanges your secret key for a short-lived access token by calling the endpoint below. Forward the response to the browser; the SDK reads it through getAccessToken. The secret key must never reach the browser — keep it in a server-side environment variable with no client-side prefix.

POST `https://api.ai-autocomplete.com/api/auth/token`

Headers

`Authorization: Bearer <sk_v1_…>` — your secret key.

Body

`product_id` — the UUID of the product the token is for. Visible in the URL of the product editor at /edit.

Request body

```json
{
  "product_id": "<uuid>"
}
```

200 OK

```json
{
  "access_token": "at_v1_AbCdEfGh...",
  "expires_at": 1775464738,
  "token_type": "Bearer"
}
```

expires_at is unix seconds. Pass it through unchanged — the SDK normalizes it.

401 Unauthorized

```json
{
  "error": {
    "code": "INVALID_SECRET_KEY",
    "message": "The provided secret key is invalid"
  }
}
```

### In the browser

The frontend SDK calls a route on your own backend (e.g. /api/ac-token), reads the access token + expiry, and returns them to the SDK. No secret-key code lives here.

**MyAutocomplete.tsx (runs in the browser)**

```tsx
// BROWSER-ONLY. No secret key here — only the URL of your own
// backend route, which holds the secret key.
<AIAutocomplete
  apiConfig={{
    type: "accessToken",
    getAccessToken: async () => {
      const res = await fetch("/api/ac-token");
      const { access_token, expires_at } = await res.json();
      return { accessToken: access_token, expiresAt: expires_at };
    },
  }}
  onSubmit={handleSubmit}
/>;
```

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `type` Required | `"accessToken"` | — | Required discriminator. |
| `getAccessToken` Required | `() => Promise<AccessTokenResult>` | — | Async function the SDK calls when it needs a token. Hit your server (which holds the secret key), exchange for an access token, and return { accessToken, expiresAt }. |
| `accessToken` | `string` | — | Initial token to avoid one round-trip on mount. |
| `endpoint` | `string` | `"https://api.ai-autocomplete.com/api/suggest"` | Optional — full URL of the suggest endpoint. Defaults to the hosted endpoint, so you only need this when self-hosting. |
| `headers` | `Record<string, string>` | — | Additional headers merged into every request. |

How refresh works

On 401, the SDK calls getAccessToken once and retries. Concurrent 401s share a single refresh. Tokens are refreshed proactively 30 seconds before expiresAt.
