The Popup Reward Store API

Authentication

Learn how authentication works in the API

Authentication Overview

The API uses JWT (JSON Web Token) based authentication to secure all endpoints for B2B integrations. This section covers the complete authentication flow and how to manage tokens in server-to-server environments.

Authentication Flow for B2B Integration

  1. API Key Setup: Obtain API credentials (username and password) from your account dashboard
  2. Token Exchange: Exchange API credentials for access and refresh tokens
  3. Server-to-Server Calls: Use the access token in the Authorization header
  4. Automated Refresh: Implement automatic token refresh in your backend services
  5. Token Revocation: Invalidate tokens when rotating credentials or ending sessions

Token Types

Access Token

  • Purpose: Used to authenticate API requests
  • Lifetime: 1 hour
  • Usage: Include in Authorization header as Bearer {token}

Refresh Token

  • Purpose: Used to obtain new access and refresh token pairs
  • Lifetime: 7 days
  • Usage: Send to /auth/refresh endpoint

IP Whitelisting

If your account has IP whitelist entries configured, API requests (including login and token refresh) must originate from a whitelisted IP address. Requests from non-whitelisted IPs will receive a 403 Forbidden response. If no whitelist entries are configured, all IPs are allowed.

Headers Required

All protected endpoints require the following header:

Authorization: Bearer {your_access_token}

Response Format

Success Responses

All authentication endpoints return responses wrapped in a standard envelope:

{
  "success": true,
  "data": {
    // response data
  }
}

Error Responses

{
  "error": {
    "name": "UnauthorizedError",
    "code": "UNAUTHORIZED",
    "message": "Invalid credentials"
  }
}

Common Error Codes

StatusError NameCodeDescription
400ValidationExceptionVALIDATION_FAILUREMissing or invalid request fields
400SyntaxErrorSYNTAX_ERRORInvalid JSON in request body
401UnauthorizedErrorUNAUTHORIZEDInvalid credentials or expired token
403ForbiddenErrorFORBIDDENIP address not authorized

Quick Start for B2B Integration

  1. Authenticate with your API credentials
  2. Extract the access_token from the data object in the response
  3. Store tokens securely in your backend infrastructure
  4. Use the token in subsequent server-to-server API calls
  5. Implement automatic token refresh before expiration

Example Implementation

# Step 1: Login and get tokens
curl -X POST {{host}}/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "username": "your_api_username",
    "password": "your_api_password"
  }'

# Response:
# {
#   "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
#   }
# }

# Step 2: Use access token for API calls
curl -X GET {{host}}/api/v1/products \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json"

# Step 3: Refresh token when needed (before access token expires)
curl -X POST {{host}}/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }'
class APIAuth {
    private $host;
    private $accessToken;
    private $refreshToken;
    private $accessExpiresAt;

    public function __construct($host) {
        $this->host = $host;
    }

    public function login($username, $password) {
        $data = json_encode([
            'username' => $username,
            'password' => $password
        ]);

        $context = stream_context_create([
            'http' => [
                'method' => 'POST',
                'header' => 'Content-Type: application/json',
                'content' => $data
            ]
        ]);

        $response = file_get_contents($this->host . '/auth/login', false, $context);
        $result = json_decode($response, true);

        if ($result && $result['success']) {
            $tokenData = $result['data'];
            $this->accessToken = $tokenData['access_token'];
            $this->refreshToken = $tokenData['refresh_token'];
            $this->accessExpiresAt = strtotime($tokenData['access_expires_at']);

            // Store tokens securely (database, cache, etc.)
            $this->storeTokens();

            return true;
        }

        return false;
    }

    public function makeAuthenticatedRequest($url, $method = 'GET', $data = null) {
        // Check if token needs refresh (5 minutes before expiry)
        if ($this->shouldRefreshToken()) {
            $this->refreshAccessToken();
        }

        $headers = [
            'Authorization: Bearer ' . $this->accessToken,
            'Content-Type: application/json'
        ];

        $context = [
            'http' => [
                'method' => $method,
                'header' => implode("\r\n", $headers)
            ]
        ];

        if ($data && in_array($method, ['POST', 'PUT', 'PATCH'])) {
            $context['http']['content'] = json_encode($data);
        }

        $response = file_get_contents($url, false, stream_context_create($context));
        return json_decode($response, true);
    }

    private function shouldRefreshToken($bufferMinutes = 5) {
        return (time() + ($bufferMinutes * 60)) >= $this->accessExpiresAt;
    }

    private function refreshAccessToken() {
        $data = json_encode(['refresh_token' => $this->refreshToken]);

        $context = stream_context_create([
            'http' => [
                'method' => 'POST',
                'header' => 'Content-Type: application/json',
                'content' => $data
            ]
        ]);

        $response = file_get_contents($this->host . '/auth/refresh', false, $context);
        $result = json_decode($response, true);

        if ($result && $result['success']) {
            $tokenData = $result['data'];
            $this->accessToken = $tokenData['access_token'];
            $this->refreshToken = $tokenData['refresh_token'];
            $this->accessExpiresAt = strtotime($tokenData['access_expires_at']);
            $this->storeTokens();
        }
    }

    private function storeTokens() {
        // Store in your preferred secure storage
        // Examples: database, Redis, encrypted file
        $_SESSION['api_access_token'] = $this->accessToken;
        $_SESSION['api_refresh_token'] = $this->refreshToken;
        $_SESSION['api_expires_at'] = $this->accessExpiresAt;
    }
}

// Usage example
$auth = new APIAuth('{{host}}');
$auth->login('your_api_username', 'your_api_password');

// Make authenticated API calls
$products = $auth->makeAuthenticatedRequest('{{host}}/api/v1/products');
$categories = $auth->makeAuthenticatedRequest('{{host}}/api/v1/categories');

Authentication Endpoints

Advanced Topics

For production applications, see our comprehensive guides on: