Authentication
Keys, the three ways to send one, and how to make a browser key safe.
Send your key as a bearer token:
Authorization: Bearer oaq_…X-API-Key: oaq_… works identically. A ?key= query parameter also works, and
should be treated as a way to prove your key works from a terminal rather than a
way to run in production — query strings end up in access logs, browser history
and Referer headers.
Two kinds of key
| Scope | What it does | Where it lives |
|---|---|---|
| read | Reads the public API on behalf of your account | Your app, your server, a browser bundle |
| sensor | Writes readings for exactly one station | The machine next to the sensor |
They are deliberately separate. A read key pasted into a web page cannot forge readings, and that is a property of the key rather than a rule our code has to remember.
Using a key in a browser
A key in client-side code is readable by anyone who opens devtools. That is inherent to shipping code to a browser, not a mistake you made.
The control is origin locking. Pin the key to your origins in your account and it stops working anywhere else — the same approach a map tile token uses.
Do not use an unlocked key in a browser. Nothing stops someone else spending your account's entire quota with it.
CORS follows the lock:
- No origins pinned →
Access-Control-Allow-Origin: *. Right for a server key. - Origins pinned → only the calling origin is reflected, with
Vary: Originso a shared cache cannot hand one site's allowance to another.
Many keys, one account
Make a key per app, per environment, and per browser origin. They cost nothing and they make it possible to revoke exactly one thing when something leaks.
They share one quota — see rate limits.
Revocation
Revoking takes effect within 30 seconds. That is a deliberate cache: the account database should not be in the hot path of every public read.