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.
| Mode | Endpoint | What changes after a successful response |
|---|---|---|
| Full pair rotation | POST /api/v1/sessions/refresh | New accessToken and refreshToken. The previous pair is invalid. |
| Access token only | POST /api/v1/sessions/refresh-access-token | New accessToken. refreshToken unchanged. |
| Refresh token only | POST /api/v1/sessions/refresh-refresh-token | New 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
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
- The session is resolved from
Authorizationand therefreshTokenbody. - 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
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
- The session is resolved from the
accessTokenhash. - The session exists, refreshToken has not expired, client type is API.
accessTokenmust not be expired at request time.- A new
accessTokenis 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
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
- The session is resolved from the
refreshTokenhash. - The session exists, refreshToken has not expired, client type is API.
- A new
refreshTokenis issued; the old one is invalid after success.