The Popup Reward Store API

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/refresh

Authentication: None required (uses refresh token in body)

Request Body

{
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Parameters

ParameterTypeRequiredDescription
refresh_tokenstringYesValid 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

FieldTypeDescription
access_tokenstringNew JWT token for API authentication (valid for 1 hour)
refresh_tokenstringNew refresh token (rotation enabled, valid for 7 days)
access_expires_atdatetimeAccess token expiration timestamp (RFC3339, UTC)
refresh_expires_atdatetimeRefresh token expiration timestamp (RFC3339, UTC)
client_idnumberYour 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

  1. Proactive Refresh: Refresh tokens 5-10 minutes before they expire to avoid API interruptions
  2. Error Handling: Always handle refresh failures and fall back to login
  3. Token Rotation: Always store the new refresh token from the response — the old one is revoked
  4. Secure Storage: Store refresh tokens securely (encrypted database, Redis, or secure vault)
  5. Retry Logic: If a 401 is received on an API call, attempt a refresh before retrying the request