# How Azeroth Auction Assassin Handles Battle.net OAuth Authentication

> Learn how Azeroth Auction Assassin manages Battle.net OAuth authentication. Discover token fetching, caching, and a robust retry mechanism for seamless integration with Blizzard APIs.

- Repository: [FF14 Advanced Market Search/azerothauctionassassin](https://github.com/ff14-advanced-market-search/azerothauctionassassin)
- Tags: how-to-guide
- Published: 2026-03-01

---

**Azeroth Auction Assassin implements Battle.net OAuth authentication through a client-credentials flow that fetches access tokens from Blizzard's identity server, caches them for 20 hours to minimize API calls, and automatically refreshes them before the 24-hour expiry window while retrying failed requests up to 10 times.**

Azeroth Auction Assassin (AAA) requires valid Battle.net OAuth tokens to query World of Warcraft auction house data via Blizzard's public APIs. The Python implementation splits authentication logic between a lightweight token fetcher in [`utils/api_requests.py`](https://github.com/ff14-advanced-market-search/azerothauctionassassin/blob/main/utils/api_requests.py) and a caching token manager in [`utils/mega_data_setup.py`](https://github.com/ff14-advanced-market-search/azerothauctionassassin/blob/main/utils/mega_data_setup.py) that ensures continuous uptime during long-running market scans.

## Storing Blizzard API Credentials

AAA expects the **Battle.net Client ID** and **Client Secret** to be available either as environment variables or within the [`mega_data.json`](https://github.com/ff14-advanced-market-search/azerothauctionassassin/blob/main/mega_data.json) configuration file. During initialization, the `MegaData.__set_mega_vars` method validates these credentials and raises an exception immediately if either value is missing, preventing runtime authentication failures during market scans.

## Client-Credentials Grant Implementation

The application uses the **OAuth 2.0 client-credentials grant** to obtain bearer tokens. Both the standalone utility and the centralized manager issue an HTTP POST request to `https://oauth.battle.net/token` with the form data `grant_type=client_credentials` and HTTP Basic authentication using the client ID and secret.

The `get_wow_access_token` function in [`utils/api_requests.py`](https://github.com/ff14-advanced-market-search/azerothauctionassassin/blob/main/utils/api_requests.py) (lines 58‑64) provides a thin wrapper around this request:

```python
import requests

def get_wow_access_token(client_id, client_secret):
    response = requests.post(
        "https://oauth.battle.net/token",
        data={"grant_type": "client_credentials"},
        auth=(client_id, client_secret),
    )
    return response.json()["access_token"]

```

## Token Caching and Automatic Refresh

To avoid hitting Blizzard's rate limits and reduce latency, the `MegaData` class implements a **20-hour token cache** that stores the access token and its creation timestamp.

### The Cache Validation Logic

The `check_access_token` method in [`utils/mega_data_setup.py`](https://github.com/ff14-advanced-market-search/azerothauctionassassin/blob/main/utils/mega_data_setup.py) (lines 44‑76) compares the current Unix time against `self.access_token_creation_unix_time`. If fewer than 20 hours (72,000 seconds) have elapsed, the existing token is returned immediately. Once the cache expires, the method fetches a fresh token and updates the timestamp, providing a four-hour safety buffer before Blizzard's standard 24-hour token expiration.

```python
from datetime import datetime
from tenacity import retry, stop_after_attempt

class MegaData:
    @retry(stop=stop_after_attempt(10))
    def check_access_token(self):
        current_time = int(datetime.now().timestamp())
        
        # Re-use token if it's younger than 20 hours

        if current_time - self.access_token_creation_unix_time < 20 * 60 * 60:
            return self.access_token
            
        # Request new token

        response = requests.post(
            "https://oauth.battle.net/token",
            data={"grant_type": "client_credentials"},
            auth=(self.WOW_CLIENT_ID, self.WOW_CLIENT_SECRET),
        )
        
        if response.status_code != 200:
            raise Exception(
                "Failed to get access token. Check your Battle.net credentials at "
                "https://develop.battle.net/access/clients"
            )
            
        self.access_token = response.json()["access_token"]
        self.access_token_creation_unix_time = current_time
        return self.access_token

```

## Using Tokens in API Requests

All Blizzard API calls attach the cached token as a **Bearer token** in the Authorization header. The format follows the OAuth 2.0 standard: `{"Authorization": f"Bearer {token}"}`.

The methods `make_ah_api_request`, `make_commodity_ah_api_request`, `get_wow_token_price`, and `get_petnames` all invoke `self.check_access_token()` to ensure valid authentication before executing their respective endpoints.

```python
headers = {"Authorization": f"Bearer {self.check_access_token()}"}
response = requests.get(
    "https://us.api.blizzard.com/data/wow/token/index",
    headers=headers,
    params={"namespace": "dynamic-us", "locale": "en_US"}
)

```

## Error Handling and Retry Logic

### Transient Failure Recovery

The authentication layer uses the `@retry` decorator from the **tenacity** library to execute up to 10 attempts with exponential backoff before raising an exception. This protects long-running scans against temporary network interruptions or brief Battle.net API outages.

### Invalid Credential Detection

When the OAuth endpoint returns a non-200 status code, `check_access_token` raises an explicit exception containing the URL `https://develop.battle.net/access/clients`, directing users to verify their Battle.net application credentials are correctly configured in [`mega_data.json`](https://github.com/ff14-advanced-market-search/azerothauctionassassin/blob/main/mega_data.json) or environment variables.

## Code Examples for Battle.net OAuth

### Standalone Token Retrieval

Use the utility function directly when building external scripts that don't require the full `MegaData` stack:

```python
from utils.api_requests import get_wow_access_token
import os

client_id = os.environ.get("WOW_CLIENT_ID")
client_secret = os.environ.get("WOW_CLIENT_SECRET")

token = get_wow_access_token(client_id, client_secret)
print(f"OAuth token: {token}")

```

### Integrated Authentication with MegaData

For production scanning, instantiate `MegaData` to benefit from automatic caching and refresh:

```python
from utils.mega_data_setup import MegaData

# Credentials loaded automatically from mega_data.json or env vars

mega = MegaData()

# Token is obtained automatically during __init__

auctions = mega.get_listings_single(realm_id=1234)
print(f"Retrieved {len(auctions)} auctions")

```

### Manual API Call with Bearer Token

When debugging or extending functionality, use the raw header format:

```python
import requests

token = "YOUR_ACCESS_TOKEN"
headers = {"Authorization": f"Bearer {token}"}
url = "https://us.api.blizzard.com/data/wow/auctions/commodities"

response = requests.get(url, headers=headers)
commodities = response.json()["auctions"]

```

## Summary

- **Client-credentials flow**: AAA authenticates to `https://oauth.battle.net/token` using HTTP Basic auth with Client ID and Secret.
- **20-hour cache**: The `MegaData.check_access_token` method caches tokens to reduce API overhead and refreshes them automatically before the 24-hour expiration.
- **Credential validation**: Missing or invalid credentials trigger immediate exceptions during initialization via `MegaData.__set_mega_vars`.
- **Resilient delivery**: The `@retry` decorator from tenacity attempts failed token requests up to 10 times before failing.
- **Standard Bearer usage**: All WoW API calls inject the token via the `Authorization: Bearer` header.

## Frequently Asked Questions

### What OAuth grant type does Azeroth Auction Assassin use?

AAA uses the **client-credentials grant** defined in OAuth 2.0. This server-to-server flow is appropriate because AAA operates as a background service without requiring user consent or interactive login sessions.

### How long does AAA cache Battle.net access tokens?

The application caches tokens for **20 hours** after acquisition. Since Blizzard tokens remain valid for 24 hours, this four-hour buffer prevents edge-case expirations during long-running market scans.

### Where does AAA store Blizzard API credentials?

Credentials are read from **environment variables** (`WOW_CLIENT_ID`, `WOW_CLIENT_SECRET`) or the [`mega_data.json`](https://github.com/ff14-advanced-market-search/azerothauctionassassin/blob/main/mega_data.json) configuration file. The `MegaData.__set_mega_vars` method validates their presence during class initialization and raises an exception if either value is missing.

### How does AAA handle token expiration during a scan?

The `check_access_token` method automatically refreshes the token when the 20-hour cache expires. Because every API call routes through this method, the scan continues uninterrupted with the new credentials without manual intervention.