On this page

Authentication

Every MIOSA API request carries a single Authorization: Bearer <token> header. The token is either an API key (prefix msk_) or a JWT from POST /auth/login.

One key covers the entire platform - computers, desktop, files, exec, CUA agent, OSA, credits, and (with the right role) admin. No separate keys for AI, no per-product configuration.

Credential hierarchy

API Keys

Key format


msk_<role>_<random>
PrefixRoleCapabilities
msk_u_...userCompute, desktop, files, CUA, OSA, credits
msk_a_...adminEverything above + /api/v1/admin/*
msk_p_...platformTenant-wide automation issued by the MIOSA platform

Role is orthogonal to purpose, which picks the backend the key can call:

  • purpose: api - compute, desktop, files, CUA, OSA, credits
  • purpose: optimal - AI/LLM proxy (/v1/chat/completions, /v1/responses)

If you need both, create two keys. They share the msk_ family so SDK configuration is identical.

Creating an API key

curl -X POST https://api.miosa.ai/api/v1/api-keys 
  -H "Authorization: Bearer YOUR_JWT_TOKEN" 
  -H "Content-Type: application/json" 
  -d '{
    "name": "Production SDK Key",
    "key_type": "user",
    "purpose": "api"
  }'
{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "key": "msk_u_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
    "key_prefix": "msk_u_a1b2c3",
    "name": "Production SDK Key",
    "key_type": "user",
    "key_purpose": "api",
    "rate_limit_rpm": 60,
    "status": "active",
    "created_at": "2026-04-17T00:00:00Z"
  }
}

User-role callers can only mint user keys. Admin and platform callers may mint any key_type. To issue admin keys programmatically, use the admin variant at POST /admin/api-keys (operator-internal - not part of the public docs).

Using an API key

Pass the key in the Authorization header:

curl https://api.miosa.ai/api/v1/computers 
  -H "Authorization: Bearer msk_u_a1b2c3d4e5f6..."

All five SDKs read MIOSA_API_KEY from the environment by default:

Managing keys

ActionEndpoint
List your keysGET /api/v1/api-keys
Create a keyPOST /api/v1/api-keys
Revoke a keyDELETE /api/v1/api-keys/{id}

Revoking a key flips its status to revoked. The change is cached and enforced within seconds - subsequent requests return 401 Unauthorized. Revocation is irreversible; create a new key if you need access restored.

Admin keys

msk_a_* and msk_p_* keys unlock everything under /api/v1/admin/* - user management, tenant operations, credit grants, fleet-wide computer control, hosted model routing. These are gated behind the same RequireAdmin plug as admin JWTs.

User-role callers hitting an admin endpoint receive 403 Forbidden.

Admin endpoints are operator-internal and not documented publicly.

Preview tokens

Preview tokens (mp_<base64url>) are short-lived signed tokens for embedding a sandbox preview in an <iframe> without exposing an msk_* key to the browser.

Your backend mints a preview token server-side and passes it to the <MiosaPreview> UI component. The component includes it automatically - no Authorization header needed in browser code.

Minting a preview token

curl -X POST https://api.miosa.ai/api/v1/sandboxes/sbx_abc123/preview-token 
  -H "Authorization: Bearer msk_u_..." 
  -H "Content-Type: application/json" 
  -d '{"expires_in": 3600}'
{
  "data": {
    "token": "mp_eyJhbGciOiJFZERTQSIs...",
    "expires_at": "2026-05-25T13:00:00Z",
    "sandbox_id": "sbx_abc123"
  }
}

In the browser, pass the token to the <MiosaPreview> component:


<MiosaPreview token="mp_eyJhbGciOiJFZERTQSIs..." sandboxId="sbx_abc123" />

See <MiosaPreview> and other UI components and the Preview Tokens API reference for the full component API and token validation spec.

  • Format: mp_<base64url> - signed, not opaque; do not attempt to decode.
  • TTL: Default 1 hour; configurable via expires_in (max 24 hours).
  • Scope: Read-only access to the specific sandbox’s preview port. Cannot create or mutate resources.
  • Revocation: Preview tokens cannot be individually revoked. Destroying the sandbox invalidates all outstanding tokens for it.

Share tokens

Share tokens (ms_<base64url>) turn a sandbox preview into a public read-only URL that anyone with the link can visit - no MIOSA account required.

Minting a share URL

curl -X POST https://api.miosa.ai/api/v1/sandboxes/sbx_abc123/shares 
  -H "Authorization: Bearer msk_u_..." 
  -H "Content-Type: application/json" 
  -d '{"expires_in": 86400}'
{
  "data": {
    "token": "ms_eyJhbGciOiJFZERTQSIs...",
    "url": "https://5173-sbx-abc123.sandbox.miosa.app?token=ms_eyJhbGciOiJFZERTQSIs...",
    "expires_at": "2026-05-26T00:00:00Z",
    "sandbox_id": "sbx_abc123"
  }
}
  • Format: ms_<base64url> - the token IS the URL query parameter (?ms=ms_...).
  • Access: Public, read-only, unauthenticated - anyone with the URL can view the preview.
  • TTL: Set via expires_in in seconds. No maximum enforced; omit for a non-expiring share.
  • Revocation: DELETE /api/v1/sandboxes/:id/shares/:token revokes immediately.

See the Sandbox Shares API reference and Integrations: Preview Tokens.


Token comparison

msk_* API keyJWTBrowser tokenmp_ Preview tokenms_ Share token
ScopeFull workspaceUser sessionSingle sandboxSingle sandbox previewSingle sandbox preview
TTLUntil revoked~1 h (refresh 7 d)Configurable (default 1 h)Configurable (default 1 h)Configurable
How to mintDashboard or POST /api/v1/api-keysPOST /api/v1/auth/loginPOST /api/v1/browser-tokensPOST /api/v1/sandboxes/:id/preview-tokenPOST /api/v1/sandboxes/:id/shares
Who uses itServerServer / browser (UI)BrowserBrowser / iframeAnyone (unauthenticated)
Can revokeYesNo (short TTL)No (short TTL)NoYes
Creates resourcesYesYesNoNoNo

White-label auth note

The tenant.preview_domain.* and tenant.branding.* configuration endpoints accept both msk_* API keys and JWTs. These are the only tenant-level config routes accessible with an API key - all other tenant administration routes require a JWT from an admin session.

# Setting a preview domain with an API key (allowed)
curl -X PUT https://api.miosa.ai/api/v1/tenant/preview-domain 
  -H "Authorization: Bearer msk_a_..." 
  -H "Content-Type: application/json" 
  -d '{"domain": "preview.yourdomain.com"}'

# Fetching tenant branding with an API key (allowed)
curl https://api.miosa.ai/api/v1/tenant/branding 
  -H "Authorization: Bearer msk_a_..."

See the Tenant Preview Domain and Tenant Branding API references for the full configuration spec.


JWT Tokens

JWT tokens are used by the MIOSA web UI and SSE ticket flows. They are issued on login and carry user identity + tenant context.

Obtaining a token

curl -X POST https://api.miosa.ai/api/v1/auth/login 
  -H "Content-Type: application/json" 
  -d '{"email": "user@example.com", "password": "your_password"}'
{
  "token": "eyJhbGciOiJIUzUxMiIs...",
  "refresh_token": "eyJhbGciOiJIUzUxMiIs...",
  "user": { "id": "...", "email": "user@example.com" }
}

Token lifecycle

TokenLifetimeRefresh
Access token~1 hourUse refresh token
Refresh token7 daysRe-login required
curl -X POST https://api.miosa.ai/api/v1/auth/refresh 
  -H "Content-Type: application/json" 
  -d '{"refresh_token": "eyJhbGciOiJIUzUxMiIs..."}'

SSE streams

Server-Sent Event endpoints (CUA session events) cannot use a standard Authorization header because EventSource does not support custom headers. Instead, mint a one-time ticket first:

# 1. Ask for a ticket (Bearer-authed  -  API key or JWT both work)
curl -X POST 
  https://api.miosa.ai/api/v1/computers/{id}/cua/sessions/{session_id}/sse-ticket 
  -H "Authorization: Bearer msk_u_..."

# {"ticket":"sset_abc123","expires_in":3600,"session_id":"..."}

# 2. Open the stream with the ticket as a query param
curl https://api.miosa.ai/api/v1/computers/{id}/cua/sessions/{session_id}/events?ticket=sset_abc123

The ticket is single-use and expires after one hour.

Rate limits

ScopeLimitWindow
Developer API (/api/v1/*)300 requestsPer minute per key
Admin API (/api/v1/admin/*)300 requestsPer minute per key
Auth endpoints (/auth/login, /auth/register, /auth/refresh)60 requestsPer minute per IP

When rate limited, the API returns 429 Too Many Requests with a Retry-After header.

Rate-limit status is surfaced in every response:


X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1712700060

Error codes

StatusCodeMeaning
401UNAUTHORIZEDMissing / invalid / revoked credential
403FORBIDDENValid credential but insufficient role
429RATE_LIMITEDToo many requests

Security best practices

  1. Never commit API keys to version control.
  2. Use environment variables or a secrets manager.
  3. Rotate keys on exposure - revoke and create a new one.
  4. Scope by role - hand out msk_u_* keys to most callers; reserve msk_a_* / msk_p_* for operational tooling.
  5. Separate keys for dev and prod - easier to revoke blast radius.
  6. Restrict by IP (admin keys) - pass allowed_ips when minting via POST /admin/api-keys to reject traffic from unexpected sources.

Was this helpful?