Skip to content

Access tokens

VAIF Studio has two kinds of routes, and they take different credentials:

Plane Examples Credential
Data plane: what your app calls /v1/data/{projectId}/{table}, storage, function invokes, realtime, /projects/{projectId}/auth/* (your app’s users) A project API key (API keys), plus the app user’s access token as Authorization: Bearer when they are signed in
Control plane: managing projects /projects/* administration, /schema-engine/*, /functions/* management, /billing/* A console access token: Authorization: Bearer <token> for a signed-in VAIF Studio user

An API key sent to a control-plane route is refused with 403 SCOPE_INSUFFICIENT.

vaif login signs you in through the browser and saves the token in ~/.vaif/auth.json (the token field), readable only by you. The CLI refreshes it when it is close to expiring.

For CI, scripts and AI agents, POST /auth/cli/login with { "email", "password" } returns a CLI token:

Terminal window
curl -X POST https://api.vaif.studio/auth/cli/login \
-H "Content-Type: application/json" \
--data '{"email":"you@example.com","password":"your-password"}'

The answer is one of:

  • { "ok": true, "accessToken", "refreshToken", "expiresIn", "user" }: you’re signed in. expiresIn is the token’s lifetime in seconds.
  • { "ok": true, "mfaRequired": true, "challengeToken", "expiresInSeconds" }: your account has two-factor authentication. Send the code from your authenticator app to POST /auth/mfa/verify with { "challengeToken", "code" } to get the token.

If your organization requires single sign-on for your email domain, a password sign-in is refused with 403; sign in with vaif login instead.

Give the token to the CLI in one of two ways:

  • Set VAIF_AUTH_TOKEN in the environment. Every command uses it instead of ~/.vaif/auth.json, and it is never saved, printed or refreshed.
  • Save it with vaif login --token < token.txt.

See Console API for agents and CI for more.

Terminal window
TOKEN=$(jq -r .token ~/.vaif/auth.json)
PROJECT_ID="your-project-id"
# Run SQL against the project (several statements are fine)
curl -X POST https://api.vaif.studio/schema-engine/query/$PROJECT_ID \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
--data '{"sql":"SELECT table_name FROM information_schema.tables WHERE table_schema = current_schema();"}'
# Apply a schema definition
curl -X POST https://api.vaif.studio/schema-engine/apply \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
--data '{
"projectId": "'$PROJECT_ID'",
"definition": {
"schemaVersion": "1.0",
"tables": [{
"name": "posts",
"columns": [
{ "name": "id", "type": "uuid", "primaryKey": true },
{ "name": "title", "type": "text", "nullable": false }
]
}]
}
}'

POST /schema-engine/preview takes the same body as apply and shows the changes without making them.

import { createVaifClient } from "@vaifstudio/client";
const vaif = createVaifClient({
baseUrl: "https://api.vaif.studio",
accessToken: process.env.VAIF_ACCESS_TOKEN,
});
// Your Verament sessions in a project
const { sessions } = await vaif.copilot.listSessions("your-project-id");
console.log(sessions.length);

accessToken can also be a function that returns the current token, so a long-running process can refresh it.

Code When What to do
TOKEN_MISSING No Authorization header Sign in
TOKEN_INVALID Bad signature or malformed token Sign in again
TOKEN_EXPIRED The token expired vaif login, or refresh
SCOPE_INSUFFICIENT An API key on a control-plane route, or a token for another project Use a console access token
PROJECT_DEACTIVATED The project is deactivated See Project deactivation
RATE_LIMITED Too many requests Wait Retry-After seconds

The full list is in Error codes. @vaifstudio/client exports the codes as the VaifErrorCode type.