# Authentication

> Every Read API request needs a Bearer token in the Authorization header.

Source: https://docs.buildonto.dev/api/auth
Section: Read API

---

Authentication\[01\]

## Authentication

One Bearer token on every request. This page covers where to get it, what it is, and what each failure actually means.

### Send the header

\[02\]

Every endpoint under `api.buildonto.dev/v1/*` reads the same header. There is no other auth scheme — no query parameter, no cookie, no signature.


```
curl https://api.buildonto.dev/v1/usage \
  -H "Authorization: Bearer onto_sk_live_YOUR_KEY"
```

`GET /v1/usage` is the cheapest way to check a key works: it costs no credits, takes no concurrency slot, and returns your plan, monthly limit and remaining balance.

### Get a key

\[03\]

Sign in

[app.buildonto.dev](https://app.buildonto.dev), then `/read/keys`. A first key is created for you automatically the first time you land there.

Copy it once

The reveal modal is the only time the full token exists anywhere outside your machine. We store a SHA-256 digest, so we cannot show it to you again and cannot recover it if you lose it — you would create a new one.

Put it somewhere it will not leak

Server-side environment variable or a secrets manager. Anyone holding the token can spend your quota and your credits.

**Never ship a key to a browser.** There is no publishable or restricted key variant — every key is a full-privilege secret. If you need to call Onto from client-side code, proxy it through your own backend.

### What a key is made of

\[04\]

A key is a fixed prefix and 24 random bytes, base64url-encoded. Nothing is encoded in it — it is an opaque lookup value, not a signed token, so it carries no account id, no scope and no expiry.


```
onto_sk_live_  +  32 random characters   =  45 characters
└───────────┘     └──────────────────┘
 13 chars          base64url of 24 bytes

The first 12 characters are stored alongside the digest. That is
"onto_sk_live" for every key, so it does not tell keys apart.
Never log anything after it.
```

### Replacing a key

\[05\]

Authentication checks the key's status on every request, so revocation takes effect on the very next call rather than at the end of a cache window. There is no propagation delay to wait out.

An account has one active key. Creating a key revokes every active key first, so the old key stops working the moment the new one exists. Revoked keys are not listed and cannot be reactivated.

**There is no zero-downtime rotation.** Update your deployment with the new key right after you create it. Calls made with the old key return 401 until you do. Keys do not expire, so you only need to replace one if it leaks.

### When auth fails

\[06\]

Every auth failure returns the same status and code, deliberately: the API does not distinguish a malformed key from a revoked one from a key that never existed, because that difference is only useful to someone guessing.

What you did · You get · Fix

No Authorization header

401 UNAUTHORIZED

Add the header

Header without the Bearer prefix, or with lowercase bearer

401 UNAUTHORIZED

It is Authorization: Bearer <key>. The prefix is case-sensitive

Key was revoked

401 UNAUTHORIZED

Use another active key, or create a new one at /read/keys

Key is fine, Free plan credits are gone

429 RATE\_LIMITED

Not an auth problem — see Rate limits + credits

Key is fine, paid plan and bought credits are gone

402 PAYMENT\_REQUIRED

Not an auth problem — see Rate limits + credits

**The most common cause of a surprise 401** is a shell that never expanded the variable. Inside single quotes, `'Bearer $ONTO_API_KEY'` is sent literally, dollar sign and all. Use double quotes.

### The other two credentials

\[07\]

Onto issues three kinds of credential. A per-site key sent to `/v1/*` is a 401 that looks like a broken key.

Credential · Looks like · Used by

Read API key

onto\_sk\_live\_… (45 chars)

Anything calling /v1/\* directly, including the local MCP server

Per-site key\[onto\_site\_…\]

The Serve SDK middleware, sent as x-onto-key — from /serve/settings

Connector token

eyJ… (a JWT)

Minted by the remote MCP connector for OAuth users; lives about 2 minutes, not issued to you

The connector token is a signed JWT and always starts `eyJ`. API keys are opaque and always start `onto_`. The API accepts both as a Bearer token on `/v1/*`, and both bill the same account. A connector token expires about 2 minutes after it is minted.

Copy as Markdown[](/api/auth.md "Open the raw Markdown")

---
## Structured Data (JSON-LD)
```json
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "Onto Docs",
  "url": "https://docs.buildonto.dev",
  "description": "How to use Onto: serve AI agents Markdown from your Next.js site, call the Read API, connect over MCP, and read the AIO score.",
  "inLanguage": "en",
  "publisher": {
    "@type": "Organization",
    "name": "Onto",
    "url": "https://buildonto.dev"
  }
}
```