Connection & Auth
Before using the Workspace Internal API, the HTTP server inside the VM must be enabled. Once enabled, there are two ways to connect:
| Method | URL | Auth | Network requirement | Use case |
|---|---|---|---|---|
| Gateway | workspace.oblien.com | Authorization: Bearer <gateway_jwt> | public_access: true | External access - your app, SDK, CI, MCP |
| Direct | 10.x.x.x:9990 | Authorization: Bearer <raw_token> | Private link from caller | Workspace-to-workspace over private network |
Both methods hit the same server and the same endpoints. The difference is how you authenticate and how the request reaches the VM.
Enable the server
Start the internal server via the Oblien API. This returns a Gateway JWT for immediate use.
import { OblienClient } from 'oblien';
import { Workspace } from 'oblien/workspace';
const client = new OblienClient({
clientId: process.env.OBLIEN_CLIENT_ID!,
clientSecret: process.env.OBLIEN_CLIENT_SECRET!,
});
const ws = new Workspace(client);
const access = await ws.apiAccess.enable('ws_a1b2c3d4');
console.log(access.token); // Gateway JWT (eyJhbG...)
console.log(access.enabled); // truePOST https://api.oblien.com/workspace/ws_a1b2c3d4/internal-api-access/enable
X-Client-ID: your_client_id
X-Client-Secret: your_client_secretcurl -X POST "https://api.oblien.com/workspace/ws_a1b2c3d4/internal-api-access/enable" \
-H "X-Client-ID: $OBLIEN_CLIENT_ID" \
-H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"Enable is idempotent - calling it on an already-enabled workspace returns a fresh JWT without restarting the server.
Gateway connection
Use the Gateway JWT to access the workspace through workspace.oblien.com. The JWT embeds the VM's private IP and port - the gateway decodes it and routes your request to the correct VM automatically.
The target workspace must have public_access: true in its network configuration. Without it, the gateway cannot reach the VM through the firewall. Enable it via the Network API:
await ws.network.update('ws_a1b2c3d4', { public_access: true });// The SDK manages tokens automatically after enabling
const files = await ws.files.list('ws_a1b2c3d4', { dirPath: '/app' });
const result = await ws.exec.run('ws_a1b2c3d4', { cmd: ['ls', '-la'] });
await ws.terminal.create('ws_a1b2c3d4', { shell: '/bin/bash' });GET https://workspace.oblien.com/files?path=/app
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...# HTTP
curl "https://workspace.oblien.com/files?path=/app" \
-H "Authorization: Bearer $GATEWAY_JWT"
# WebSocket
wscat -c "wss://workspace.oblien.com/ws" \
-H "Authorization: Bearer $GATEWAY_JWT"The URL is workspace.oblien.com/endpoint - not workspace.oblien.com/ws_id/endpoint. Routing is handled by the JWT payload, not the URL path.
Token lifetime
The standard Gateway JWT expires after ~1 hour. You have two options to manage this:
- Rotate - call
rotateTokenor re-enable to get a fresh short-lived JWT - Long-lived - call
workspaceTokento get a 30-day JWT, suitable for SDKs, MCP servers, and CI pipelines
Both token types work the same way - Authorization: Bearer <token> against workspace.oblien.com. The only difference is expiry.
Direct connection
For workspace-to-workspace communication, connect directly to the target VM's private IP. This bypasses the gateway entirely - lower latency, no JWT overhead.
Setup flow
1. Enable the server on the target workspace
2. Create a private link from caller → target
3. Get the raw token + private IP of the target
4. Call the target directly from the calling workspaceStep 1: Enable the target
await ws.apiAccess.enable('ws_target');Step 2: Create a private link
Private links open a network path between two workspaces. Without a link, VMs cannot reach each other - they are network-dark by default. The link whitelists the caller's IP in the target workspace's firewall.
await ws.network.update('ws_target', {
private_link_ids: ['ws_caller'],
});The private_link_ids field takes workspace IDs, not IPs. The platform resolves each ID to its internal IP and configures the target's firewall automatically. See Private Links for details.
Step 3: Get the raw connection token
The raw token is a hex string used directly by the VM's auth middleware. Unlike the Gateway JWT, it doesn't embed routing info - you provide the IP yourself.
const raw = await ws.apiAccess.rawToken('ws_target');
console.log(raw.token); // "a1b2c3d4e5f6..."
console.log(raw.ip); // "10.0.1.42"
console.log(raw.port); // 9990See the full endpoint reference at Raw token.
Step 4: Call from the other workspace
From code running inside ws_caller, call ws_target directly over the private network:
// Running inside ws_caller
const res = await fetch('http://10.0.1.42:9990/files?path=/app', {
headers: { 'Authorization': `Bearer ${raw.token}` },
});
const files = await res.json();curl "http://10.0.1.42:9990/exec" \
-H "Authorization: Bearer a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{"cmd":["npm","test"]}'Direct calls go VM-to-VM - no gateway, no JWT encoding/decoding overhead. This is the lowest-latency way to interact with a workspace.
Disable the server
Stop the internal server, kill all sessions, and close connections.
await ws.apiAccess.disable('ws_a1b2c3d4');See the full endpoint reference at Disable server.
Token comparison
| Gateway JWT | Raw Connection Token | |
|---|---|---|
| Use with | workspace.oblien.com | Direct 10.x.x.x:9990 |
| Auth header | Authorization: Bearer <jwt> | Authorization: Bearer <raw_token> |
| Lifetime | ~1 hour (standard) or 30 days (workspace token) | Until rotated |
| Contains VM IP | Yes (embedded in JWT) | No (you get the IP separately) |
| How to get | enable / rotateToken / workspaceToken | rawToken |
| When to use | External access - apps, SDK, CI, MCP | Workspace-to-workspace orchestration |
Full API access reference
All server management endpoints are on the Oblien API at api.oblien.com:
| Endpoint | Method | Description |
|---|---|---|
/workspace/:id/internal-api-access | GET | Server status |
/workspace/:id/internal-api-access/enable | POST | Enable server |
/workspace/:id/internal-api-access/disable | POST | Disable server |
/workspace/:id/internal-api-access/token | POST | Rotate token |
/workspace/:id/internal-api-access/token/raw | GET | Raw token + IP |
/workspace/:id/internal-api-access/reconnect | POST | Reconnect |
/workspace/:id/internal-api-access/workspace | POST | 30-day token |