Skip to content

Access tokens

Users sign in with a zero-knowledge proof; machines use an access token. An access token is the sanctioned, non-ZK, machine-to-machine credential — a scoped, expiring key a script, server, CI job, or serverless function presents instead of running a login. It authenticates as the app (like an app key), never as a human user.

mk_<env>_at_<32 hex>
│ │
│ └ at = access token
└ live | test

An access token carries an explicit set of scopes (what it may do) and an expiry (when it stops working). It’s revocable at any time.

Scopes are resource-level. A token is granted a subset of:

ScopeGrants
db:read / db:writeRead / write the app’s database tables
kv:read / kv:writeRead / write app KV
storage:read / storage:writeRead / write file storage
messages:read / messages:writeRead / write space messages
functions:invokeInvoke serverless functions
ai:inferRun AI inference

A request is rejected (403) if the token lacks the scope the route requires — e.g. a db:read-only token cannot insert a row.

Open your app → Access tokens → choose scopes, environment, and an expiry, then Create. The mk_<env>_at_… secret is shown once — copy it now.

An access token is presented on the same X-Muhkoo-Key header as an app key, so it works anywhere a key does.

import { Client } from "@muhkoo/connect";
// Headless / server-side client — no ZK identity, just the token.
const client = new Client({ accessToken: process.env.MUHKOO_ACCESS_TOKEN });
await client.db("orders").query({ where: [{ column: "status", op: "eq", value: "open" }] });

accessToken takes precedence over apiKey when both are set.

Serverless functions get one automatically

Section titled “Serverless functions get one automatically”

You don’t have to embed a token in a serverless function. The platform mints a scoped access token per function and injects it as env.MUHKOO_ACCESS_TOKEN (and mirrors it to env.MUHKOO_APP_KEY). That’s what lets a function act as the server-side gateway to backend-only tables:

export default {
async fetch(request, env) {
const client = new Client({
apiKey: env.MUHKOO_APP_KEY, // the injected access token
baseUrl: env.MUHKOO_API_URL,
});
// your own authorization here, then reach sensitive data:
const rows = await client.db("audit_log").query({ limit: 50 });
return Response.json(rows);
},
};
  • Expiry — set at creation (default 90 days, up to 365). After it expires the token stops resolving; mint a new one.
  • Revocation — revoke from the portal, muhkoo tokens revoke, or client.accessTokens.revoke(...). Revocation takes effect within the auth cache window (seconds), not at expiry.
  • Rotation — create the new token, deploy it, then revoke the old one.
Publishable key (pk)Secret key (sk)Access token (at)
Browser-safeYesNoNo
ScopedNo (full)No (full)Yes
ExpiresNoNoYes
Reaches backend-only tablesNoYesYes (with db:*)

Reach for an access token whenever a machine needs least-privilege, time-boxed access — CI, a server, or a function gating sensitive data.