ShopifyAutoAuth README

The project's README from github.com/AhmadHassan-BTed/ShopifyAutoAuth. As one markdown file: README.md.

ShopifyAutoAuth Banner

ShopifyAutoAuth

Enterprise-Grade Shopify OAuth 2.0 Client Credentials Adapter

A zero-friction, production-hardened bridge connecting legacy Shopify applications to modern Client Credentials Grant authentication.

CI Status PyPI Version Python Versions License Maintainer


Overview

Following Shopify's mandatory authentication migration on January 1, 2026, static shpat_xxx custom app tokens were deprecated in favor of OAuth 2.0 Client Credentials Grant short-lived access tokens (RFC 6749 §4.4).

shopify_auth_adapter provides a transparent authentication proxy. Existing applications can preserve their variable assignment patterns while under the hood tokens are acquired, cached in volatile RAM, and refreshed prior to expiration without runtime interruption.

Migration: Before vs After

# BEFORE (Deprecated static token):
SHOPIFY_ACCESS_TOKEN = "shpat_xxxxxxxxxxxxxxxxxxxxxxxx"

# AFTER (Automatic OAuth 2.0 token with auto-refresh):
from shopify_auth_adapter import get_access_token

SHOPIFY_ACCESS_TOKEN = get_access_token()

⚡ Quick Start: 1 Line of Code

To upgrade any Python application to Shopify's modern OAuth 2.0 authentication, replace your deprecated shpat_xxx string with get_access_token():

from shopify_auth_adapter import get_access_token

# Automatically fetches, caches in RAM, and auto-refreshes OAuth 2.0 tokens:
SHOPIFY_ACCESS_TOKEN = get_access_token()

That's it! Everything else (OAuth 2.0 requests, RAM caching, automatic 24h refresh) happens automatically behind the scenes.

Installation

pip install shopify-auth-adapter

Setting Up Credentials

You can supply your Shopify Dev Dashboard credentials in any of 3 ways:

Create a .env file in your project root:

SHOPIFY_SHOP=your-store.myshopify.com
SHOPIFY_CLIENT_ID=your_client_id
SHOPIFY_CLIENT_SECRET=your_client_secret

Option B: Environment Variables (Production / Docker / Cloud)

Set variables in your terminal or deployment environment:

export SHOPIFY_SHOP="your-store.myshopify.com"
export SHOPIFY_CLIENT_ID="your_client_id"
export SHOPIFY_CLIENT_SECRET="your_client_secret"

Option C: Pass Directly in Python Code

from shopify_auth_adapter import get_access_token

token = get_access_token(
    shop="your-store.myshopify.com",
    client_id="your_client_id",
    client_secret="your_client_secret",
)

Testing Credentials

You can verify your Dev Dashboard credentials and store connection instantly by running the included tester script:

python examples/test_credentials.py

Usage Examples

1. Drop-In Token Helper

import httpx

from shopify_auth_adapter import get_access_token

# Automatically reads credentials from .env or environment variables:
headers = {"X-Shopify-Access-Token": get_access_token()}
response = httpx.get(
    "https://your-store.myshopify.com/admin/api/2026-07/shop.json",
    headers=headers,
)

2. High-Level Shopify Client

from shopify_auth_adapter import ShopifyClient

# Automatically attaches tokens and retries on 401:
client = ShopifyClient()

# REST API call
blogs = client.get("/blogs.json").json()["blogs"]

# GraphQL API call
shop_info = client.graphql("""
    query {
        shop {
            name
            email
        }
    }
""")

Feature Matrix

Domain Capability Architectural Mechanism
Authentication OAuth 2.0 Client Credentials Grant Automatic POST /admin/oauth/access_token exchange for Dev Dashboard apps.
Concurrency Thundering Herd Protection Re-entrant threading.RLock double-checked locking mechanism.
Resilience Clock-Skew Mitigation 300-second (5-minute) proactive expiration cutoff buffer.
Header Integration Transparent LiveToken Proxy Custom str subclass executing JIT encoding delegation during HTTP header resolution.
Client Abstraction High-Level ShopifyClient Integrated REST & GraphQL client with automatic 401 cache-invalidation and single retry.
Security Zero Credential Leak Guarantee String masking on repr, str, and tracebacks (LiveToken(<masked>)).

System Architecture & Domain Boundaries

The codebase follows domain-driven modularity principles with contract-based interfaces (Protocol) to guarantee zero coupling and total separation of concerns.

flowchart TD
    subgraph AppLayer["Client Application Layer"]
        App["Application Codebase"]
        Env["Environment Config (.env)"]
    end

    subgraph PkgDomain["shopify_auth_adapter Package"]
        Facade["API Facade"]
        Config["ShopifyConfig"]
        Proxy["LiveToken Proxy"]
        Manager["TokenManager"]
        Cache["InMemoryTokenCache"]
        Provider["OAuth2ClientCredentialsProvider"]
        Client["ShopifyClient"]
    end

    subgraph ExtInfra["External Infrastructure"]
        ShopifyAuth["Shopify OAuth Endpoint"]
        ShopifyAPI["Shopify Admin API"]
    end

    Env --> Config
    App --> Facade
    Facade --> Manager
    Manager --> Provider
    
    App --> Proxy
    Proxy --> Manager
    Manager --> Cache
    Manager --> Provider
    Provider --> ShopifyAuth

    App --> Client
    Client --> Proxy
    Client --> ShopifyAPI

Request Lifecycle & Token Resolution

The diagram below illustrates the exact sequence executed when an HTTP request header formats the LiveToken string proxy:

sequenceDiagram
    autonumber
    participant App as Client Application
    participant Proxy as LiveToken Proxy
    participant Manager as TokenManager
    participant Cache as InMemoryTokenCache
    participant Provider as OAuth2Provider
    participant Shopify as Shopify Server

    App->>Proxy: Header resolution (.encode)
    Proxy->>Manager: get_token()
    Manager->>Cache: get()
    
    alt Cache Hit (Valid Token)
        Cache-->>Manager: CachedToken
    else Cache Miss / Expired
        Manager->>Manager: Acquire Lock
        Manager->>Provider: fetch_token()
        Provider->>Shopify: POST /admin/oauth/access_token
        Shopify-->>Provider: 200 OK Token Response
        Provider-->>Manager: access_token
        Manager->>Cache: set()
    end
    
    Manager-->>Proxy: access_token string
    Proxy-->>App: Encoded Token Bytes

Repository Structure

ShopifyAutoAuth/
├── src/
│   └── shopify_auth_adapter/      # Primary Python package
│       ├── auth/                  # OAuth2 provider, token manager, LiveToken proxy
│       ├── cache/                 # In-memory token cache implementation
│       ├── client/                # ShopifyClient REST and GraphQL helper
│       └── core/                  # Configuration, constants, exceptions, protocols
├── docs/                          # In-depth technical documentation
├── tests/                         # Unit and integration test suite
├── .github/                       # GitHub Actions workflows & community templates
├── pyproject.toml                 # Packaging & tool configurations
└── README.md                      # Project overview & documentation

Technical Deep Dives

Clock-Skew Math & Expiration Buffer

Shopify Client Credentials Grant tokens carry a fixed duration of 86,399 seconds (~24 hours).

To prevent edge cases where a token is valid when read from cache but expires while in flight across the network, the expiration cutoff is calculated as:

$$\text{Cutoff} = T_{\text{expiry}} - 300\text{ seconds}$$

Any token within 5 minutes of expiration is treated as invalid, forcing a fresh token fetch prior to request dispatch.

Security Invariants & Token Masking

Credentials and raw access tokens are strictly protected against unintentional exposure in logs, error reports, and inspection tools:

  • repr(LiveToken) returns "LiveToken(<masked>)".
  • repr(ShopifyConfig) outputs client_secret=<redacted>.
  • repr(CachedToken) outputs access_token=<redacted>.
  • Exception messages exclude credential strings under all circumstances.
Development & Tooling Shortcuts

Common developer tasks are managed via the project Makefile:

# Install editable package with dev tools
make install

# Run linter and type checks
make lint
make typecheck

# Run full test suite with coverage
make test

Build & CI/CD Pipeline

The project utilizes GitHub Actions for continuous quality verification and release automation:

flowchart LR
    Push["Code Push / Tag"] --> Lint["Ruff Linter"]
    Push --> TypeCheck["Mypy Strict Check"]
    Push --> Test["Pytest Suite"]
    
    Lint --> Build["Hatchling Build"]
    TypeCheck --> Build
    Test --> Build

    Build --> PyPI["Publish to PyPI Registry"]

License

This project is licensed under the terms of the MIT License.


Engineered by Ahmad Hassan (B-Ted) 💚

GitHub Profile • PyPI Package • LinkedIn

ShopifyAutoAuth (AhmadHassan-BTed/ShopifyAutoAuth)

Searching Database…

What is this?ShopifyAutoAuth is a Python library that handles Shopify Admin API OAuth 2.0 Client Credentials Grant authentication, automatically fetching, caching, and refreshing access tokens so you never touch a raw token.
Is this a library I import, or a standalone app?It is a Python library installed as a PyPI package (shopifyautoauth). You import it into your existing Shopify app and swap your old token string for a call to getaccesstoken().
How do I add this to my Shopify app?Install the package, then supply your Shopify Dev Dashboard client credentials either in a .env file, as environment variables, or directly in Python code, and call getaccesstoken() where you used to hardcode a token.
What credentials do I need to use it?You need OAuth Client Credentials Grant credentials from your Shopify Dev Dashboard app (client ID and client secret), not the old shpat_xxx custom app token.
Do my old shpat_xxx tokens still work?No. Shopify deprecated static shpat_xxx custom app tokens on January 1, 2026 in favor of short-lived OAuth 2.0 Client Credentials Grant tokens, which is exactly what this library manages for you.
How long do tokens last and when does it refresh them?Shopify's Client Credentials Grant tokens last about 24 hours (86,399 seconds). The library treats a token as expired 5 minutes (300 seconds) before its real expiry to avoid network-latency clock-skew issues, then fetches a fresh one.
What happens if many requests need a token at the same time?A re-entrant threading.RLock with double-checked locking prevents a 'thundering herd' of simultaneous token-refresh requests, so only one fetch happens even under concurrent load.
Could my client secret or access token leak into logs?No. The internal LiveToken, ShopifyConfig, and CachedToken objects override repr and str to mask secrets, so credentials never appear in printed output, exceptions, or tracebacks.
What does the included ShopifyClient give me beyond raw token handling?ShopifyClient is a high-level REST and GraphQL client built on top of the token adapter that automatically invalidates its cache and retries once if a request gets a 401 response.
Size
0.4 MB
Stars
1.1K
Age
1mo
Commits · 90 Days