Pax8 Partner Authorization

This guide is recommended for 3rd party vendors & applications that are getting Pax8 partner authorization so they can call and use Pax8 partner data in their own applications.

Developing Delegation Applications for Pax8 APIs

Overview

This guide is intended for third-party application developers who want to integrate with Pax8's public APIs on behalf of Pax8 partners. If you're a Pax8 partner looking to use third-party applications, please review this guide.

What is Delegated Authorization?

Delegated Authorization is the process of obtaining a Pax8 Partner's consent to call Pax8's Public APIs on their behalf. Before you can access any partner data, the partner must explicitly provide consent through the OAuth2 Authorization Code Grant flow.

When a partner authorizes your application, they will see a consent screen similar to this:

Getting Started

1. Initial Setup

  1. Contact Pax8: Send an email to [email protected] to discuss your integration use case.
  2. Receive Credentials: Pax8 will review your use case and provide:
    • Sandbox credentials
    • Vendor Portal access
    • API keys
    • Client ID and Client Secret for OAuth

2. Implementation Overview

Pax8 follows the standard OAuth2 Authorization Code flow with a few specific requirements. If you're familiar with OAuth2, you can likely adapt your existing implementation with minimal changes. The main Pax8-specific requirement is the mandatory audience parameter.

Implementing the OAuth2 Flow

Step 1: Create an Integration Page

Build a page in your application where Pax8 partners can:

  • Learn about your Pax8 integration
  • Initiate the authorization process via an "Integrate with Pax8" button

Step 2: Request Authorization

We recommend using Auth0 libraries for whatever coding language you are comfortable with: API docs

In general, the following is how to go about retrieving tokens:

When a partner clicks your integration button, redirect them to the Pax8 authorization endpoint:

https://login.pax8.com/authorize

Required Parameters

ParameterValueDescription
response_typecodeSpecifies that you're using the authorization code flow
client_id<your clientId>The client ID provided by Pax8
scopeManage:Pax8DataThe permissions you're requesting (see Supported Scopes section)
redirect_uri<your redirect uri>The URL where Pax8 will send the authorization code (must be pre-registered with Pax8)
audiencehttps://api.pax8.comRequired - Specifies that you're requesting access to the Pax8 API

Security Parameters

ParameterDescription
stateA random value you generate to prevent CSRF attacks. Store this value in your session and verify it when Pax8 redirects back to your application.
nonceA random value used to prevent replay attacks. This value will be included in the ID token if you request the openid scope.

Example Authorization URL

https://login.pax8.com/authorize?
response_type=code&
client_id=<your clientId>&
scope=Manage:Pax8Data&
state=<your state>&
redirect_uri=<your redirect uri>&
nonce=<your nonce>&
audience=https://api.pax8.com

Step 3: Handle the Authorization Response

After the partner authorizes your application, Pax8 will redirect to your redirect_uri with an authorization code:

https://<your-redirect-url>?code=<authorization code>
  1. Verify that the state parameter matches the value you sent in Step 2
  2. Extract the code parameter from the URL

Step 4: Exchange the Code for Tokens

Make a POST request to exchange the authorization code for access and refresh tokens:

Endpoint:

POST https://login.pax8.com/oauth/token

Headers:

Content-Type: application/json

Request Body:

{
  "grant_type": "authorization_code",
  "code": "<authorization code from Step 3>",
  "client_id": "<your clientId>",
  "client_secret": "<your clientSecret>",
  "redirect_uri": "<your redirect uri>"
}

Response:

{
  "access_token": "<access_token>",
  "id_token": "<id_token>",         // Only included if you requested the 'openid' scope
  "refresh_token": "<refresh_token>", // Only included if you requested the 'offline_access' scope
  "scope": "<granted scopes>",
  "expires_in": 86400,              // Token validity in seconds (24 hours)
  "token_type": "Bearer"
}

Token Lifetimes

  • Access Token: Valid for 24 hours (86400 seconds)
  • Refresh Token:
    • Absolute lifetime: 1 year (31,557,600 seconds)
    • Inactivity lifetime: 30 days (2,592,000 seconds)
    • Each use of the refresh token resets the inactivity timer

Step 5: Use the Access Token

Include the access token in the Authorization header when calling Pax8 APIs:

Authorization: Bearer <access_token>

For detailed API documentation, see the Pax8 API Reference.

Step 6: Refresh the Access Token (Optional)

If you requested the offline_access scope and received a refresh token, you can use it to obtain a new access token when the current one expires:

Endpoint:

POST https://login.pax8.com/oauth/token

Request Body:

{
  "grant_type": "refresh_token",
  "refresh_token": "<refresh_token>",
  "client_id": "<your clientId>",
  "client_secret": "<your clientSecret>"
}

Supported Scopes

ScopeDescription
Manage:Pax8DataAccess to partner's Pax8 data (orders, subscriptions, contacts, products & invoices). Currently, this is the only data scope available. More granular scopes will be available in the future.
emailAccess to the user's email address
profileAccess to basic profile information
openidWhen requested, the response will include an ID token with the user's identity
offline_accessWhen requested, the response will include a refresh token

Sequence Diagram


Testing Notes

  • Important: Your Vendor Portal account cannot be used to test the delegation flow. Only Pax8 Partner accounts will work.
  • If you are logged into the Vendor Portal (https://integrations.pax8.com), you must test the login flow in a new browser or incognito window to avoid granting consent with your Integrator account instead of a Partner account.

Python Auth0 Example for Pax8 API Integration

This example demonstrates how to implement the OAuth2 authorization flow for Pax8 APIs using the Auth0 Python SDK.

Prerequisites

Install the required packages:

pip install auth0-python requests

Simple OAuth2 Client

import time
import requests
from auth0.authentication import GetToken
from urllib.parse import urlencode

class Pax8AuthClient:
    # Pax8 OAuth2 configuration
    DOMAIN = "login.pax8.com"
    CLIENT_ID = "YOUR_CLIENT_ID"
    CLIENT_SECRET = "YOUR_CLIENT_SECRET"
    REDIRECT_URI = "https://your-app.com/callback"
    AUDIENCE = "https://api.pax8.com"
    SCOPE = "Manage:Pax8Data offline_access"
    
    def __init__(self):
        self.access_token = None
        self.refresh_token = None
        self.expires_at = 0
        self.auth0_client = GetToken(self.DOMAIN)
    
    def get_authorization_url(self):
        """Generate the authorization URL to redirect the user to"""
        # Build the authorization URL with all required parameters
        # The Auth0 SDK will handle state parameter automatically
        params = {
            'response_type': 'code',
            'client_id': self.CLIENT_ID,
            'redirect_uri': self.REDIRECT_URI,
            'scope': self.SCOPE,
            'audience': self.AUDIENCE
        }
        
        query_string = urlencode(params)
        authorization_url = f'https://{self.DOMAIN}/authorize?{query_string}'
        
        return authorization_url
    
    def exchange_code(self, code):
        """Exchange the authorization code for tokens"""
        # Exchange the code for tokens using Auth0 SDK
        token_data = self.auth0_client.authorization_code(
            client_id=self.CLIENT_ID,
            client_secret=self.CLIENT_SECRET,
            code=code,
            redirect_uri=self.REDIRECT_URI
        )
        
        self.access_token = token_data.get('access_token')
        self.refresh_token = token_data.get('refresh_token')
        self.expires_at = time.time() + token_data.get('expires_in', 86400)
        
        return token_data
    
    def refresh_token_if_needed(self):
        """Refresh the access token if it's expired"""
        if not self.refresh_token:
            raise ValueError("No refresh token available")
        
        if time.time() >= self.expires_at:
            token_data = self.auth0_client.refresh_token(
                client_id=self.CLIENT_ID,
                client_secret=self.CLIENT_SECRET,
                refresh_token=self.refresh_token
            )
            
            self.access_token = token_data.get('access_token')
            self.expires_at = time.time() + token_data.get('expires_in', 86400)
            
            # The refresh token might be rotated, so update it if a new one is provided
            if 'refresh_token' in token_data:
                self.refresh_token = token_data.get('refresh_token')
    
    def call_api(self, endpoint):
        """Make a request to the Pax8 API (placeholder)"""
        self.refresh_token_if_needed()
        
        # In a real implementation, you would make an actual API call here
        # This is just a placeholder to show how to use the access token
        print(f"Calling API endpoint: {endpoint}")
        print(f"Using access token: {self.access_token[:10]}...")
        
        # Example of how you would make the actual API call:
        # headers = {"Authorization": f"Bearer {self.access_token}"}
        # response = requests.get(f"https://api.pax8.com{endpoint}", headers=headers)
        # return response.json()
        
        return {"message": "This is a placeholder for the API response"}

Minimal Usage Example

from flask import Flask, request, redirect, jsonify

app = Flask(__name__)
app.secret_key = "your-secret-key"  # Replace with a real secret key

### Create an instance of the Pax8AuthClient
auth_client = Pax8AuthClient()

@app.route("/login")
def login():
    """Step 1: Redirect user to Pax8 authorization page"""
    auth_url = auth_client.get_authorization_url()
    return redirect(auth_url)

@app.route("/callback")
def callback():
    """Step 2: Handle the callback and exchange code for tokens"""
    code = request.args.get("code")
    
    try:
        auth_client.exchange_code(code)
        return "Authorization successful! You can now use the access token to call Pax8 APIs."
    except Exception as e:
        return f"Error: {str(e)}", 400

@app.route("/api-example")
def api_example():
    """Example of calling an API with the access token"""
    try:
        # This is just a placeholder - replace with your actual API endpoint
        result = auth_client.call_api("/your-api-endpoint")
        return jsonify(result)
    except Exception as e:
        return f"Error: {str(e)}", 400

if __name__ == "__main__":
    app.run(debug=True)

Usage Notes

  1. Replace YOUR_CLIENT_ID and YOUR_CLIENT_SECRET with the credentials provided by Pax8.
  2. Update REDIRECT_URI to match the callback URL registered with Pax8.
  3. This example uses Flask for simplicity, but the Pax8AuthClient class can be used with any Python web framework.
  4. The call_api method is a placeholder - replace it with your actual API calls.
  5. The Auth0 Python SDK handles security features like state parameter management automatically.

Security Considerations

  1. Always use HTTPS for all communication.
  2. Store client secrets securely and never expose them in client-side code.
  3. In production, store tokens securely, not in the session as shown in this example.
  4. Use a strong, randomly generated secret key for your Flask application.

Troubleshooting

If you encounter issues during implementation, please contact [email protected] for assistance.