Skip to content

Rotate tunnel credential

POST
/api/devices/{device_id}/tunnel-credential/rotate
curl --request POST \
--url 'https://example.com/api/devices/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/tunnel-credential/rotate?organization_id=2489E9AD-2EE2-8E00-8EC9-32D5F69181C0' \
--header 'Authorization: Bearer <token>'

Revoke all active tunnel credentials and issue a new one.

Authorisation (BUG-501 / GC-BE-03): org OWNER or ADMIN only (org_owner admits both – ADMIN ranks above OWNER in ORG_ROLE_RANK). The new raw token authenticates to frps AS the device, so it must never be reachable with a plain OTA MEMBER role. Every rotation appends a tunnel_credential.rotated shell-audit event (no secret in the payload), committed in the same transaction as the rotation.

The raw sotc_ token is returned ONCE in this response. The device must store it in the update-safe /data/frp/credential path (see the Go agent’s creds.SaveCredential).

Revoked credentials are kept in the database for audit history but are no longer usable for authentication.

Returns 404 if the device does not belong to the organisation.

device_id
required
Device Id
string format: uuid
organization_id
required
Organization Id
string format: uuid

Successful Response

Media type application/json
TunnelCredentialRotateResponse

Response after a successful credential rotation.

tunnel_token is the NEW raw sotc_ value — shown ONCE. Store it securely on the device at /data/frp/credential.

object
rotated_at
required
Rotated At
string format: date-time
rotation_count
required
Rotation Count
integer
tunnel_token
required
Tunnel Token
string
tunnel_token_prefix
required
Tunnel Token Prefix
string
Example generated
{
"rotated_at": "2026-04-15T12:00:00Z",
"rotation_count": 1,
"tunnel_token": "example",
"tunnel_token_prefix": "example"
}

Validation Error

Media type application/json
HTTPValidationError
object
detail
Detail
Array<object>
ValidationError
object
ctx
Context
object
input
Input
loc
required
Location
Array
msg
required
Message
string
type
required
Error Type
string
Example generated
{
"detail": [
{
"ctx": {},
"input": "example",
"loc": [
"example"
],
"msg": "example",
"type": "example"
}
]
}