Skip to main content

Creating an API Key

Stealthium uses API keys to authenticate agents running on your machines. This guide shows you how to sign in via the REST API and generate a key entirely from the command line — no UI required after the initial OAuth step.


How Authentication Works

Stealthium signs users in through GitHub or Google OAuth. (Deployments can also enable email/password login — GET /api/v1/auth/methods tells you what yours supports.)

Domain restriction: Only email addresses whose domain belongs to an active Stealthium customer can log in. If you get a domain_not_allowed error, contact your Stealthium administrator to register your company's email domain.

The flow is:

  1. You open the OAuth login URL in a browser once.
  2. After approving, Stealthium redirects back to your frontend_url with a short-lived, single-use code in the URL.
  3. You exchange that code for a JWT session token at POST /api/v1/auth/token.
  4. You use the JWT as a Bearer token for all subsequent API calls, including creating API keys.

Step 1 — Trigger OAuth Login

Open one of these URLs in a browser, choosing your preferred provider:

GitHub:

https://api.backend.stealthium.io/api/v1/auth/github?frontend_url=http://localhost:5173

Google:

https://api.backend.stealthium.io/api/v1/auth/google?frontend_url=http://localhost:5173
frontend_url

The frontend_url is where Stealthium will redirect after login, appending ?code=<auth-code>. For local use, http://localhost:5173 works fine. The URL must be on the Stealthium allowlist — if you get an Invalid Frontend URL error, contact your admin to add your URL.

After you approve the OAuth prompt, your browser will be redirected to:

http://localhost:5173/auth/callback?code=<AUTH-CODE>

Copy the code value from the URL. It is not a session token yet — it's a single-use authorization code that must be exchanged in the next step.

The code expires in 1 minute

Auth codes are single-use and expire ~60 seconds after they're issued. If the exchange in Step 2 fails for any reason, the code is burned — restart from Step 1.


Step 2 — Exchange the Code for a Token

curl -s -X POST https://api.backend.stealthium.io/api/v1/auth/token \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"code": "<AUTH-CODE>",
"redirect_uri": "http://localhost:5173"
}'

redirect_uri must be exactly the frontend_url you started the flow with, or the exchange fails with a 401.

Response:

{
"access_token": "<YOUR-JWT>",
"refresh_token": "<YOUR-REFRESH-TOKEN>",
"token_type": "Bearer",
"expires_in": 21600
}

access_token is your session JWT — use it as the Bearer token in every call below. (Browsers that omit the Accept: application/json header get the session as HttpOnly cookies instead; that's what the Stealthium web app uses.)

Token lifetimes

The access token lasts 6 hours. When it expires, get a fresh one with your refresh token instead of logging in again:

curl -s -X POST https://api.backend.stealthium.io/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"refresh_token": "<YOUR-REFRESH-TOKEN>"}'

Refresh tokens last 24 hours and are not extended by use, so a session caps out at 24 hours before you must log in again.


Step 3 — Verify Your Session (Optional)

Confirm the token works and see your user info:

curl -s https://api.backend.stealthium.io/api/v1/me \
-H "Authorization: Bearer <YOUR-JWT>"

Response:

{
"user": {
"id": 1,
"email": "you@yourcompany.com",
"name": "Your Name",
"avatar": "https://..."
}
}

Step 4 — Create an API Key

An API key belongs to a workspace, so the request must name one (you must be an owner or member of it). List your workspaces first if you don't know the id:

curl -s https://api.backend.stealthium.io/api/v1/workspaces/ \
-H "Authorization: Bearer <YOUR-JWT>"

Then create the key:

curl -s -X POST https://api.backend.stealthium.io/api/v1/keys/ \
-H "Authorization: Bearer <YOUR-JWT>" \
-H "Content-Type: application/json" \
-d '{
"name": "Northeast Cluster",
"description": "Production GPU hosts",
"workspace_id": 1
}'

Response (201 Created):

{
"api_key": {
"id": 42,
"name": "Northeast Cluster",
"key": "4e0234cd-307a-4f9a-a8e3-eb237752763d",
"description": "Production GPU hosts",
"workspace_id": 1,
"workspace_name": "Production",
"customer_id": 1,
"is_active": true,
"expires_at": "",
"last_used_at": "",
"created_at": "2026-03-19T10:00:00Z",
"updated_at": "2026-03-19T10:00:00Z"
},
"message": "API key created successfully"
}
Key format

API keys are plain UUIDs — no prefix. The agent validates the format and refuses to start with anything else, so always copy the key exactly as returned.


Step 5 — Use the Key in Your Agent

Paste the key into your Stealthium agent configuration.

Debian / Ubuntu package

echo "[orion]" | sudo tee /etc/stealthium/config.toml
echo 'api_key = "4e0234cd-307a-4f9a-a8e3-eb237752763d"' | sudo tee -a /etc/stealthium/config.toml

Docker environment variable

docker run -d \
--name stealthium-agent \
-e STEALTHIUM_API_KEY="4e0234cd-307a-4f9a-a8e3-eb237752763d" \
-e LD_LIBRARY_PATH="/host-usr/lib:/host-usr/local/lib:/home/kubernetes/bin/nvidia/lib64" \
--restart always \
--privileged \
--cap-add NET_ADMIN \
--pid host \
-v /sys/kernel/debug:/sys/kernel/debug:ro \
-v /sys/fs/bpf:/sys/fs/bpf \
-v /lib/modules:/lib/modules:ro \
-v /proc:/host/proc:ro \
-v /sys:/host/sys:ro \
-v /sys/kernel/tracing:/sys/kernel/tracing \
-v /run/dbus/system_bus_socket:/run/dbus/system_bus_socket:rw \
-v /etc/stealthium:/etc/stealthium:rw \
-v /usr:/host-usr:ro \
registry.backend.stealthium.io/stealthium/release:latest

Helm (Kubernetes)

helm upgrade --install stealthium-agent \
oci://registry.backend.stealthium.io/stealthium/release/stealthium-agent \
--namespace stealthium \
--create-namespace \
--set stealthium.apiKey=4e0234cd-307a-4f9a-a8e3-eb237752763d \
--set registryCredentials.registry=registry.backend.stealthium.io \
--set registryCredentials.create=true \
--set registryCredentials.username=harbor-user \
--set registryCredentials.password='harbor-password'

Without --version, Helm installs the latest published chart. To see what's available:

helm show chart oci://registry.backend.stealthium.io/stealthium/release/stealthium-agent

Other Key Management Commands

List all your keys

curl -s https://api.backend.stealthium.io/api/v1/keys/ \
-H "Authorization: Bearer <YOUR-JWT>"

Rotate a key

Generates a new secret for an existing key while keeping its id and history:

curl -s -X POST https://api.backend.stealthium.io/api/v1/keys/<key-id>/rotate \
-H "Authorization: Bearer <YOUR-JWT>"

Delete a key

curl -s -X DELETE https://api.backend.stealthium.io/api/v1/keys/<key-id> \
-H "Authorization: Bearer <YOUR-JWT>"

Troubleshooting

"domain_not_allowed" after OAuth

Your email domain doesn't belong to an active Stealthium customer. Ask a Stealthium admin to register your company's email domain.

"Invalid Frontend URL"

The frontend_url you passed is not on the server's allowlist. Use an approved URL (e.g. http://localhost:5173 for local use) or ask your admin to add your URL.

"Invalid Code" when exchanging

Auth codes are single-use and expire after ~1 minute, and the redirect_uri in the exchange must exactly match the frontend_url the flow started with. A failed attempt burns the code — restart from Step 1.

GitHub login — no email found

If your GitHub email is set to private, Stealthium automatically fetches your email from the GitHub API. Make sure your GitHub account's primary email address is verified.

Compromised key

Rotate it — the key id stays the same, so nothing else needs updating on the Stealthium side:

curl -s -X POST https://api.backend.stealthium.io/api/v1/keys/<key-id>/rotate \
-H "Authorization: Bearer <YOUR-JWT>"

Then update your agent configuration with the new key value.