Refresh Token
Refresh access tokens using refresh tokens
Refresh Token
Obtain a new access and refresh token pair using a valid refresh token without requiring the user to log in again.
Endpoint
POST /auth/refreshAuthentication: None required (uses refresh token in body)
Request Body
{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| refresh_token | string | Yes | Valid refresh token from login |
Response
Success (200 OK)
{
"success": true,
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"access_expires_at": "2024-01-15T10:30:00Z",
"refresh_expires_at": "2024-01-22T09:30:00Z",
"client_id": 123456
}
}Response Fields
| Field | Type | Description |
|---|---|---|
| access_token | string | New JWT token for API authentication (valid for 1 hour) |
| refresh_token | string | New refresh token (rotation enabled, valid for 7 days) |
| access_expires_at | datetime | Access token expiration timestamp (RFC3339, UTC) |
| refresh_expires_at | datetime | Refresh token expiration timestamp (RFC3339, UTC) |
| client_id | number | Your unique client identifier |
Token Rotation
When you refresh tokens, the old refresh token is revoked and a completely new token pair (access + refresh) is issued. Always store the new refresh token from the response for subsequent refreshes.
Error Responses
400 Bad Request
Invalid JSON syntax:
{
"error": {
"name": "SyntaxError",
"code": "SYNTAX_ERROR",
"message": "Invalid request body"
}
}Missing required fields:
{
"error": {
"name": "ValidationException",
"code": "VALIDATION_FAILURE",
"message": "Refresh token is required"
}
}401 Unauthorized
{
"error": {
"name": "UnauthorizedError",
"code": "UNAUTHORIZED",
"message": "Invalid refresh token"
}
}This is also returned when the refresh token has expired or has already been revoked.
403 Forbidden
Returned when IP whitelisting is configured and the request originates from a non-whitelisted IP:
{
"error": {
"name": "ForbiddenError",
"code": "FORBIDDEN",
"message": "IP address not authorized"
}
}Examples
curl -X POST {{host}}/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'<?php
$data = [
'refresh_token' => $stored_refresh_token
];
$ch = curl_init('{{host}}/auth/refresh');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$result = json_decode($response, true);
if ($result['success']) {
$newAccessToken = $result['data']['access_token'];
// Important: Store the new refresh token for future refreshes
$newRefreshToken = $result['data']['refresh_token'];
}
curl_close($ch);
?>Best Practices
- Proactive Refresh: Refresh tokens 5-10 minutes before they expire to avoid API interruptions
- Error Handling: Always handle refresh failures and fall back to login
- Token Rotation: Always store the new refresh token from the response — the old one is revoked
- Secure Storage: Store refresh tokens securely (encrypted database, Redis, or secure vault)
- Retry Logic: If a 401 is received on an API call, attempt a refresh before retrying the request