Tunnel
Device grants, tunnel tickets of at most 30 seconds, one-time browser links and the client side of the tunnel.
Create a tunnel ticket
Mint a tunnel ticket of at most 30 s for a granted device, signed by that device, at the session's current epoch.
The owner, or a member with a live grant, else 403 not_allowed; a member's answer carries its role.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | The session's ID. |
Ciresk-Tunnel | string | Optional | the tunnel protocol the client speaks. With 2, the ticket is keyed (its signed claims carry tunnel_pin, the worker's per-epoch certificate pin) when the installation turned end to end on, the session's worker reported its pin for the epoch and every polling relay announced v2; a keyed ticket's streams are TLS 1.3 end to end and the worker refuses a v1 open on it. Absent or 1: an unkeyed ticket |
Request body
device_public_key- ed25519 public key
device_signature- ed25519 over dev-ticket:<session>:<signed_at>, base64url
signed_at- unix seconds
Response
epochexpires_atkinds- stream kinds and capabilities, minted from the caller's role and the policy
relay_urlssh_host_key- the epoch's openssh host key once the worker reported it; a renewal refreshes known_hosts
sync- true only for the creating device
ticketticket_id
curl -X POST "$CIRESK_API/v1/dev/sessions/devs_0166ba8e973a3df1b173b30df1cb8f2f/tickets" \
-H "Authorization: Bearer $CIRESK_KEY" \
-H "Content-Type: application/json" \
-d '{
"device_public_key": "q3Vt1kYwZ8Xo2Jc9bN4rTe7LmA0sPfHgD6iUyW5xCzE",
"device_signature": "Z2Jm0X4pR8sQk1vT7wYc3nL6eHa9uD2fB5gJiM0oKtN7rPqS1xVyW4zA8cE6lU3dG9hF2jI5kO7mQ0nR4sT1uV",
"signed_at": 1
}'Grant a device
Grant a device access to the session's tunnel (the creating device is granted at create).
The owner, or a member with a live grant, else 403 not_allowed. An attached device may not open sync.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | The session's ID. |
Request body
device_namedevice_public_key
Response
created_atidprincipalsession_id
Errors
- 403not_allowed
curl -X POST "$CIRESK_API/v1/dev/sessions/devs_0166ba8e973a3df1b173b30df1cb8f2f/grants" \
-H "Authorization: Bearer $CIRESK_KEY" \
-H "Content-Type: application/json" \
-d '{
"device_name": "maya-laptop",
"device_public_key": "q3Vt1kYwZ8Xo2Jc9bN4rTe7LmA0sPfHgD6iUyW5xCzE"
}'Revoke a device grant
Revoke a device grant; the relay closes that device's connections at once.
Owner only, or a principal with dev:sessions.kill (audited).
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | The session's ID. |
grant_id | string | Required | The grant's ID. |
Response
revoked
Errors
- 404an error
curl -X DELETE "$CIRESK_API/v1/dev/sessions/devs_0166ba8e973a3df1b173b30df1cb8f2f/grants/devg_01d7f828cd2d8a17550e8d59d6319b9f" \
-H "Authorization: Bearer $CIRESK_KEY"Open a session in the browser
A one-time, 60-second link that opens one http port, the diff, the terminal or VS Code Web of the session in the browser.
The owner, or a member whose grant passes its re-check, else 403 not_allowed; a person only. The answer's url is on the gateway's preview host (<target>--<label>--<session>.<cell>.<preview-domain>) and carries a dvh_ handoff, valid once and for 60 s, bound to session, epoch, target, principal, member and role, which ciresk-dev-gateway redeems with dev.gateway.redeem. The target is an http port, diff, term (the session's shell through the gateway's ssh client: ssh for owner and use under web use when their kinds hold ssh, else ssh_ro when they hold it; ssh deny refuses it) or ide (VS Code Web: ide for owner and use under web use, else ide_ro). Refused 403 web_off when the organisation's policy has web off, 403 ssh_off for term when ssh is denied, 403 web_ide_off for ide when web_ide is off, 409 session_not_running when the session is not placed, 422 target_not_exposed when the port is not an http port of the session, 503 web_unavailable when the installation has no preview domain.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
session_id | string | Required | The session's ID. |
Request body
target- an http port of the session's expose in decimal, diff, term (the terminal) or ide (VS Code Web)
Response
expires_at- 60 s after the call; the handoff is valid once
url- https://<target>--<label>--<session>.<cell>.<preview-domain>/__ciresk/gateway/redeem?handoff=dvh_...
curl -X POST "$CIRESK_API/v1/dev/sessions/devs_0166ba8e973a3df1b173b30df1cb8f2f/web_handoff" \
-H "Authorization: Bearer $CIRESK_KEY" \
-H "Content-Type: application/json" \
-d '{
"target": "3000"
}'Open the client tunnel
The developer side of the tunnel (WebSocket upgrade, a nonce signed by the device key, then yamux).
Authorization carries a dvt_ ticket. Protocol The relay answers every websocket upgrade with Ciresk-Tunnel 1 with 101 and checks the ticket after it, in band: a refusal is a {"refused": {"code"}} message in place of the nonce or of the ok, then the close, with code invalid_ticket (the ticket does not verify or names another session or grant), stale_epoch, killed, revoked, feed_stale (the relay's feed is silent and it fails closed), draining (the relay is restarting), invalid_device (the device did not prove its key over the relay's nonce) or limit_exceeded. Every stream the worker verifies, ping excepted, is counted in the worker's per-minute streams window, audited as dev.tunnel.connect when the window opened a stream, and read with dev.connections.list.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
Ciresk-Tunnel | string | Required |
Response
switching protocols; the ticket is checked in band after it
Errors
- 400not_a_tunnel_upgrade: not a websocket upgrade, or without Ciresk-Tunnel: 1
curl "$CIRESK_API/v1/dev/tunnel/client" \
-H "Authorization: Bearer $CIRESK_KEY" \
-H "Ciresk-Tunnel: acme/platform"