# Auth

> Use when setting up or verifying Zeabur API access for Toolkit skills. Use when ZEABUR_API_KEY is missing, when any Zeabur GraphQL call returns an authentication error, or when the user asks "how do I log in to Zeabur", "set up my Zeabur token", or "am I authenticated". Prefer this over the CLI-based zeabur-* skills for server operations — this one talks to the GraphQL API directly and needs no CLI.

- Skill: `zeabur/auth` (Agent Skill)
- Install (CLI): `npx skillmds@latest add zeabur/auth`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zeabur/auth/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: zeabur (https://skillmd.com/u/zeabur)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/zeabur/auth

---


# Zeabur Toolkit Auth

All Toolkit skills call the Zeabur GraphQL API at `https://api.zeabur.com/graphql` with curl. There is no CLI. Authentication is a personal **Access Token** passed as a Bearer token.

## Getting a token

If `ZEABUR_API_KEY` is not set, walk the user through this — the token is created in the browser, not by you:

1. Open <https://zeabur.com> and sign in.
2. Go to **Settings → API Keys** (Account section).
3. Click **Create Access Token**, give it a description (e.g. `toolkit`), pick an expiration (30 days by default), and create it.
4. Copy the token immediately — it is shown only once.
5. Store it — **prefer the token file**, which every session picks up automatically (an `export` in the chat only lives in that one shell, and pasting the token into the conversation leaves it in the transcript):

```bash
mkdir -p ~/.config/zeabur
touch ~/.config/zeabur/toolkit-token && chmod 600 ~/.config/zeabur/toolkit-token
# then have the user paste the token into that file themselves (e.g. open it in an editor),
# or set it in their shell profile instead:
export ZEABUR_API_KEY="<token>"
```

Never write the token into any file that could be committed, and avoid having the user paste it into the chat — the transcript keeps it.

If neither the env var nor the token file exists but the Zeabur CLI is logged in on this machine (`~/.config/zeabur/cli.yaml`), you **may offer** to reuse that token — but say so before using it, never silently, and suggest saving it into the token file so future sessions are set.

> Tokens currently have full account access (fine-grained scopes are coming). Treat it like a password: never print it, never log it, never send it to any host other than `api.zeabur.com` — and never copy it onto a rented server.

## The standard API call pattern

Every Toolkit skill uses this pattern. The token goes into a `chmod 600` curl config passed with `-K`, never as a `-H` argument on the command line (command-line arguments are visible in the process list):

```bash
TOKEN="${ZEABUR_API_KEY:-$([ -f ~/.config/zeabur/toolkit-token ] && cat ~/.config/zeabur/toolkit-token)}"
[ -n "$TOKEN" ] || { echo "No Zeabur token — set ZEABUR_API_KEY or create ~/.config/zeabur/toolkit-token (see the auth skill)" >&2; exit 1; }
ZAPI_CFG=$(mktemp)
chmod 600 "$ZAPI_CFG"
trap 'rm -f "$ZAPI_CFG"' EXIT
printf 'header = "Authorization: Bearer %s"\n' "$TOKEN" > "$ZAPI_CFG"

zapi() {
  curl -sS -K "$ZAPI_CFG" -H "Content-Type: application/json" \
    --data-binary "$1" https://api.zeabur.com/graphql
}
```

Always check the response for GraphQL errors before using `data`. When a response passes through a shell variable, print it with `printf '%s\n'`, **never `echo`** — under `sh`/`zsh`, `echo` expands the `\n` escapes inside JSON strings (multi-line fields like `resolvedDockerfile`, `failureSummary`, or server `events` messages) into raw newlines, corrupting the JSON so `jq` fails with an "unescaped control character" error that looks like an API bug:

```bash
RESP=$(zapi '{"query":"{ me { username email } }"}')
printf '%s\n' "$RESP" | jq -e '.errors' >/dev/null && { printf '%s\n' "$RESP" | jq '.errors[].message' >&2; exit 1; }
printf '%s\n' "$RESP" | jq '.data.me'
```

## Verifying access

The call above doubles as the verification: if it returns the user's `username`, the token works. If it returns an authentication error, the token is missing, expired, or revoked — create a new one via the steps above.

## Team workspaces

Toolkit operations default to the user's personal workspace. Mutations and queries that support team resources take an optional `ownerID` argument (the team ID) — pass it only when the user explicitly wants to operate on a team's resources.

