Rehearse authorization without pretending it is production.
The sandbox is a loopback-only development host for credential issuance, revocation, public-data reads, idempotency, webhooks, replay, and sanitized inspection.
The sandbox is disabled in production and stores state in the current process. It is not a deployed public base URL, developer account system, durable credential service, or production webhook product.
What exists
| Capability | Behavior | Production implication |
|---|---|---|
| Registration | Creates a process-local developer, App, and immutable sandbox version 0.1.0. | No external account or submission. |
| Credential issuance | Reveals one plaintext Bearer value once; persists only a hash and nonsecret metadata. | No durable production credential. |
| Public Artist and Catalog reads | Require that active local credential and return the exact public response contracts. | No private grants or extra fields. |
| Revocation | Takes effect immediately for later local requests and emits credential.revoked. | No production revocation service. |
| Console actions | Require Idempotency-Key and store one process-local result. | No durable job or audit system. |
| Inspection | Shows sanitized request metadata and local lifecycle records. | Not a production log stream. |
Keep the credential server-side
import { parsePublicArtistResponse } from "@casset/apps"
const credential = process.env.CASSET_SANDBOX_CREDENTIAL
if (!credential) throw new Error("Missing local sandbox credential")
const requestId = "server-sandbox-artist-001"
const response = await fetch("http://127.0.0.1:3000/api/sandbox/v1/artists/connor", {
headers: {
accept: "application/json",
authorization: "Bearer " + credential,
"x-request-id": requestId,
},
})
const responseRequestId = response.headers.get("x-request-id")
const body: unknown = await response.json()
if (responseRequestId !== requestId || !response.ok) {
throw new Error("Casset sandbox request failed")
}
const artist = parsePublicArtistResponse(body)
// Return only artist. Keep credential and diagnostics in this server process.- Never use a
VITE_,NEXT_PUBLIC_, or other browser-exposed variable. - Never log the credential, Authorization header, credential prefix, webhook secret, request or response body, private handle or query string, App ID, database ID, or media URL.
- Do not return a credential through React props, route JSON, an error, or client inspection.
Issue, use, and revoke
- Open the authenticated Developer Portal on a local Casset process.
- Register one process-local App.
- Issue a credential and copy the plaintext value once.
- Place it in the Headless starter's server-only
.env.local. - Read
/api/sandbox/v1/artists/connoror its Catalog counterpart through the development proxy. - Revoke it and confirm the next read returns
401 INVALID_CREDENTIAL.
Idempotent console actions
Idempotency-Keyis required and accepts at most 128 text characters.- Keys are scoped by console action type. The same key and same action payload replay the stored result; concurrent duplicates coalesce.
- Reusing a key with a different payload for the same action type returns
409 INVALID_REQUEST. The same text may be used by a different action type because it has a separate scope. - Replayed credential and webhook results redact plaintext credentials and signing secrets.
Sanitized inspection
The local console records request ID, method, normalized route template, status, stable error code, and time. Internal process-local relationships may be visible inside the console, but do not copy App IDs or credential prefixes into application logs. Authorization values and request/response bodies stay hidden.
Continue with local webhook rehearsal, safe logging, or the generated starter.