Sign in and API keys
How people sign in to Cubicle (email and password, Google, cubicle login device flow) and reset a password, how programs authenticate with service account API keys (cbk_), which routes read and write keys can call, how to create, expire, revoke and use keys, and what happens to Boxes when a key, service account or member is removed.
Cubicle has two kinds of credentials. People sign in, and get a sign-in session. Programs, such as the SDK, CI jobs and agents, use an API key that belongs to a service account.
| Sign-in session | Service account API key | |
|---|---|---|
| Who uses it | A person | A program |
| How you get one | Sign in to the Dashboard, or run cubicle login | An organization owner or admin creates it with cubicle api-keys create or in the Dashboard |
| Lifetime | 30 days from sign-in | Until it is revoked, or until its expiry if it was created with one (1 to 3650 days) |
| What it can call | The routes your roles and grants allow | Box, snapshot and operation routes in its own organization |
| Token prefix | jvs_ | cbk_ |
Both are sent the same way, as Authorization: Bearer <token>. HTTP API
authentication covers the header and authentication errors.
Sign in as a person
Cubicle is invite-only: a Cubicle operator creates your account for your email address and sends
you an invitation. Sign in to the Dashboard at https://app.cubicle.sh in one of these ways:
- Email and password. The invitation email has a single-use link, valid for 72 hours, that opens the Dashboard so you can set a password of at least 12 characters. Then sign in with your email address and that password.
- Google. When the sign-in page shows Continue with Google, you can sign in with a Google account whose verified email address is the one on your invitation. The first Google sign-in links that Google account to your Cubicle account; a different Google account cannot sign in to it later.
A Google account with any other email address gets
no Cubicle account for <email>; ask an administrator for an invitation.
To give a colleague access to your organization, see Add a person.
Reset your password
Choose Forgot password? on the sign-in page and enter your email address. If it has an account, Cubicle emails a single-use link that expires after 1 hour; asking again within 5 minutes sends no second email. This also works when your invitation link has expired. Setting a new password signs out all your other sessions, including CLI logins.
Log in to the CLI
cubicle login uses a device flow: the CLI shows a code, and you approve it in the Dashboard.
Nothing connects back to your computer, so it also works over SSH and behind NAT.
-
Run
cubicle login. It prints a link and a code:To log in, open: https://app.cubicle.sh/device?user_code=WDJB-MJHT and confirm the code WDJB-MJHT. Press Enter to open the browser… -
Press Enter to open the link, with
openon macOS orxdg-openon Linux, or open it yourself. The prompt appears only on a terminal and without--no-browser. The CLI checks for your approval every 2 s, whether or not you press Enter. -
Sign in if needed, check that the page shows the same code and choose Authorize.
-
The CLI stores the session and prints
Logged in as <your email>.
The code expires after 10 minutes; run cubicle login again if it does. Choosing Deny ends
the login with login was denied in the browser. cubicle whoami prints your identity and your
role in each organization.
The CLI keeps one login at a time, and logging in again replaces it. Files the CLI writes lists where it stores the token.
Sessions and signing out
cubicle sessions listlists your Dashboard and CLI sign-ins, andcubicle sessions revoke IDends one. In the Dashboard, they are under Account → Sessions.cubicle logoutdisconnects the private network, ends the session and removes the stored login.- After 30 days, or once the session is revoked, the CLI prints
login expired; run `cubicle login`.
Service accounts and API keys
A service account is a non-interactive member of one organization, named ORG/NAME, such as
acme/ci. It never signs in and cannot join other organizations. Its API keys authenticate as
the service account.
Only an owner or admin of the organization can manage service accounts and keys, and only while signed in: API keys can never manage service accounts or keys.
Create a service account and a key
-
Create the service account:
cubicle service-accounts create --org acme ciIt prints
created acme/ci (<ID>). Its role ismember. Pass--role adminto let it start, stop, hibernate, delete, snapshot and restore every Box in the organization; running commands still needs a grant. It gets one on every Box it creates, and an owner or admin grants it other Boxes with its ID. -
Create an API key for it:
cubicle api-keys create --org acme ci github-actions --scope write --expires-days 90It prints the key, then
Store this key now; it is not shown again. -
Store the key in your secret manager or your CI system's secrets.
In the Dashboard, open Account and use Service accounts: enter a name and a role and choose
Create, then choose New key next to the account. The key dialog has Name, Scope
(which starts as read) and Expires after days. Choose Create key; the dialog shows the
key once, with Copy key.
| Setting | Values |
|---|---|
| Service account name | Lowercase letters, digits and dashes, up to 63 characters. See Names. |
| Key name | Lowercase letters, digits, ., _ and -, up to 63 characters. See Names. |
| Scope | read or write |
| Expiry | 1 to 3650 days with --expires-days. Without it, the key never expires. |
Routes that accept API keys
API keys work only on GET /v1/me and the Box, snapshot and operation routes, and only in their
own organization: other organizations' resources return 404, and a read key can send only
GET requests. Every other authenticated route returns 403 api_key_not_allowed, so a service
account cannot SSH into a Box, join the private network or open the console; it runs commands with
exec, and those commands cannot rely on sudo.
HTTP API authentication lists the routes.
The key is shown once
Cubicle stores only a SHA-256 digest of the key and its first 12 characters, which listings show as a hint. A lost key cannot be recovered: create a new one and revoke the old one.
Revoke a key or delete a service account
cubicle service-accounts list --org acme
cubicle api-keys revoke --org acme ci KEY_ID
cubicle service-accounts rm --org acme ciservice-accounts listprints each account and its keys, with their IDs.api-keys revokerevokes one key. In the Dashboard, choose Revoke next to the key.service-accounts rmdeletes the account and frees its name. In the Dashboard, choose Delete next to the account.
A key also stops working when it expires, or when its service account leaves the organization. A
key that no longer works gets 401 unauthenticated with "API key is invalid, expired or revoked".
When a key, service account or member is removed
Boxes belong to the organization, not to whoever created them. Revoking a key, deleting a service account or removing a person never stops or deletes a Box.
- A key is revoked or expires. Only that key stops working. The service account keeps its other keys, its grants and its Boxes.
- A service account is deleted, with
cubicle service-accounts rmorcubicle members rm. Its membership, keys and grants end, and its guest account in each Box is locked; its files stay in the Box. A new service account with the same name gets a new ID and none of the old grants. - A person is removed with
cubicle members rm. Their grants in the organization stop working, which ends their exec, SSH, private network and console access to its Boxes. API keys they created keep working. If they are added back, their earlier grants apply again.
Boxes that the service account or person created stay as they were:
- A running Box keeps running until it hibernates automatically. Stopped and hibernated Boxes keep their CPU, memory and disk reserved.
- Owners and admins can still start, stop, hibernate, snapshot, restore and delete them.
- Running commands in them needs a grant. Anyone else who holds one keeps it; otherwise an owner or admin adds one.
Before you delete a service account, delete the Boxes it no longer needs.
Use an API key
new Cubicle() reads CB_SDK_API_URL and CB_SDK_API_KEY. The apiUrl and apiKey options
override them.
import { Cubicle } from "@cubicle/sdk"
const cubicle = new Cubicle({
apiUrl: "https://api.cubicle.sh",
apiKey: process.env.CB_SDK_API_KEY,
})
const me = await cubicle.me()
console.log(me.identity, me.apiKey?.scope) // => acme/ci writeAll keys of one service account share its rate limits.
Keep keys secret
Keep API keys out of browsers and repositories
A write key can create Boxes, run commands in them and delete them, until it is revoked.
- Never put a key in browser code or a front-end bundle. Call Cubicle from a server, a CI job or another trusted process. The API sends no CORS headers, so browsers cannot call it directly.
- Never commit a key. Keep it in your CI system's secrets or a secret manager, pass it as
CB_SDK_API_KEY, and keep.envfiles out of version control. - Give each program its own key, with the
readscope when it only reads and an expiry, so that you can revoke one key without affecting others. - If a key leaks, revoke it with
cubicle api-keys revokeand create a new one.
Related
- Organizations and access: roles, grants and what each one allows.
- Manage organization members: add and remove people and give them Boxes.
- Run CI jobs in Boxes: run Boxes from CI.
- HTTP API authentication: bearer tokens and authentication errors.
- Account and access commands: every
login,sessions,service-accounts,api-keysandgrantscommand.
Install the CLI
Install the cubicle CLI on macOS or Linux (x64 or arm64) with the one-line installer or by hand with a SHA-256 checksum, add the optional root tunnel for SSH and the private network, upgrade, uninstall and log in.
Use cases
End-to-end walkthroughs for reaching a goal with Cubicle Boxes, such as giving an AI agent a virtual machine to run code in, running CI jobs in a fresh Box per run and setting up remote development environments for a team.

