Scoped tokens for private content
Mint a short-lived, per-user token on your own server so the browser never holds a key that can see everything.
A scoped token lets a browser search a specific slice of your data — one partition, a set of indexes, an extra filter — without ever holding a key broad enough to search everything. You mint it on your own server, per request or per session, from a key that never reaches the browser.
Claims
A scoped token is an HMAC-signed claim set:
The signing secret
Minting a token means signing the ScopedTokenClaims shape above with HMAC-SHA256. The secret for that HMAC is not your raw search key — it is a signing secret, returned exactly once, alongside the key itself, when you create a search key:
secret is the public bearer key — safe to ship to the browser as api-key on <suo-search> or in createSuoClient({ apiKey }). signingSecret is the opposite: it never leaves your server. Store it the same way you would a database credential, next to (but distinct from) the key it was issued with.
Sign scoped tokens with @suo/client/server, which exports exactly one signer and takes the signing secret, never the account's master secret:
The API verifies a scoped token by re-deriving the same signing secret from its own master secret and keyId at request time — it is never stored, on either side. A leaked scoped token exposes only what its claims allow, for as long as exp allows it, and cannot be used to mint another token. A leaked signing secret is more serious — it can sign tokens for any claims — so rotate it the same way you would rotate the key: there is no separate rotation endpoint, creating a new search key issues a new signing secret.
Only a search key gets a signingSecret; admin and write keys never carry one, since a scoped token only ever narrows a search key.
pnpm suo keys create does not print signingSecret yet — call POST /1/keys directly (see API keys) until the CLI catches up, and copy it from the JSON response the same way you would secret.
Using one
Pass the token instead of a search key:
Every claim except ratePerMinute is required, and each is checked when the token is used. A token that is missing a claim, has a claim of the wrong type, or carries more than 10 filters is refused with 401, the same as a bad signature. ratePerMinute defaults to null when left out.
Expiry and rotation
The API refuses a token whose exp is more than 24 hours past the time of the request, so a token cannot be made to live for months. Keep exp far shorter than that — minutes, not hours — and mint a new token on each page load or session refresh rather than caching one long-term. A short expiry means a token that leaks (in a browser history, a shared screenshot, a log) stops being useful quickly.
When you do not need one
If your content is public and not partitioned, a search key with an index and referrer restriction (see API keys) is enough — scoped tokens exist for the case a shared key cannot cover safely: content that must be isolated per user.