Saltar al contenido principal

API token rotation

Purpose

Starting with Passwork 7.6.0, the API includes two additional endpoints that let you renew accessToken or refreshToken independently. Together with the existing POST /api/v1/sessions/refresh, which rotates the full pair, there are three endpoints for token rotation over API sessions. The same applies to sessions for service accounts created when API tokens are generated.

ModeEndpointWhat changes after a successful response
Full pair rotationPOST /api/v1/sessions/refreshNew accessToken and refreshToken. The previous pair is invalid.
Access token onlyPOST /api/v1/sessions/refresh-access-tokenNew accessToken. refreshToken unchanged.
Refresh token onlyPOST /api/v1/sessions/refresh-refresh-tokenNew refreshToken. accessToken valid until it expires.

General information

The refresh-access-token and refresh-refresh-token endpoints apply to sessions with client type API. The backend does not distinguish a person from a service account—only the session type matters. The classic POST /api/v1/sessions/refresh is used to renew the full pair in the usual flow (including after accessTokenExpired).

By default, Passwork returns API payloads in Base64. To get JSON in the response body, send X-Response-Format: raw. See the X-Response-Format section in the API overview.

The accessTokenExpiredAt and refreshTokenExpiredAt fields are Unix timestamps (seconds). The response includes only the field(s) that apply to the token(s) returned (both fields when the full pair is rotated).

Pair rotation: POST /api/v1/sessions/refresh

Returns a new accessToken and refreshToken. After success, the previous pair is invalid. Typical case: 401 with accessTokenExpired — the client sends the current tokens and receives a new pair.

The body contains refreshToken. The Authorization header carries the current access token (including an expired one) so the server can identify the session.

Sample request

curl -s --request POST \
--url "https://passwork.example.com/api/v1/sessions/refresh" \
--header 'Content-Type: application/json' \
--header 'X-Response-Format: raw' \
--header "Authorization: Bearer 7FmKp2nQ8vRt3WxYz9Bc1Dg4Hj6Lo5Ns0Ue+SmVaXoI=" \
--data "{\"refreshToken\": \"2XkQp3oR9wSu4VyZa0Cd2Eh5Ik7Mp6Ot1Vf+TnWbYpJ=\"}" | jq .

Sample response

{
"accessToken": "9GnLq4pS0xTv5WzAb1De3Fi6Jl8Nq7Pu2Wg+UoXcZqK=",
"refreshToken": "0HoMr5qT1yUw6XaBc2Ef4Gj7Km9Or8Qv3Xh/VpYdArL=",
"accessTokenExpiredAt": 1775814596,
"refreshTokenExpiredAt": 1782990596
}

Behavior

  1. The session is resolved from Authorization and the refreshToken body.
  2. A new API token pair is issued; the old pair is invalidated.

accessToken rotation: POST /api/v1/sessions/refresh-access-token

Issues a new accessToken; refreshToken on the server is unchanged. Use this to extend a short-lived accessToken token without touching refreshToken.

Sample request

curl -s --request POST \
--url "https://passwork.example.com/api/v1/sessions/refresh-access-token" \
--header 'Content-Type: application/json' \
--header 'X-Response-Format: raw' \
--data "{\"accessToken\": \"JpNs6rWa2bXc8YdZ0ePq4fGh5Ij1Kl+Mn7Ro9StUvWx=\"}" | jq .

Sample response

{
"accessToken": "KqOt7sXb3cYd9ZeA1fQr5gHi6Jk2Lm+No8Sp0TuVwXy=",
"accessTokenExpiredAt": 1775820103
}

Behavior

  1. The session is resolved from the accessToken hash.
  2. The session exists, refreshToken has not expired, client type is API.
  3. accessToken must not be expired at request time.
  4. A new accessToken is issued; the old one is invalid after success.

refreshToken rotation: POST /api/v1/sessions/refresh-refresh-token

Issues a new refreshToken; the current accessToken stays valid until its own expiry. Useful for rotating a long-lived refreshToken without invalidating the current accessToken.

Sample request

curl -s --request POST \
--url "https://passwork.example.com/api/v1/sessions/refresh-refresh-token" \
--header 'Content-Type: application/json' \
--header 'X-Response-Format: raw' \
--data "{\"refreshToken\": \"LrPu8tYc4dZe0AfB2gRs6hJk7Kl3Mn+Op9Tq1UvWxYz=\"}" | jq .

Sample response

{
"refreshToken": "MsQv9uZd5eAf1BgC3hSt7iKl8Lm4No+Pq0Ur2VwXzA0=",
"refreshTokenExpiredAt": 1782999124
}

Behavior

  1. The session is resolved from the refreshToken hash.
  2. The session exists, refreshToken has not expired, client type is API.
  3. A new refreshToken is issued; the old one is invalid after success.