-
Notifications
You must be signed in to change notification settings - Fork 390
Feature/oauth client credentials 2026 #786
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
lvalics
wants to merge
4
commits into
Shopify:main
from
lvalics:feature/oauth-client-credentials-2026
Closed
Feature/oauth client credentials 2026 #786
lvalics
wants to merge
4
commits into
Shopify:main
from
lvalics:feature/oauth-client-credentials-2026
+864
−1
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Implements OAuth 2.0 Client Credentials Grant (RFC 6749 Section 4.4) with
intelligent automatic version detection for Shopify API 2026-01+.
Key Features:
============
1. Automatic Version Detection
- API >= 2026-01: Automatically uses Client Credentials Grant
- API < 2026-01: Automatically uses Authorization Code Grant
- Method: Session._requires_client_credentials()
2. Smart Unified Method (RECOMMENDED)
- Session.request_access_token() - Auto-selects correct OAuth flow
- No need to know which method to use
- Works with all API versions transparently
3. Manual Client Credentials Method
- Session.request_token_client_credentials() - Explicit OAuth 2.0 flow
- Returns: {'access_token', 'scope', 'expires_in': 86399}
- Token expires after 24 hours
4. Safety Guards
- Legacy request_token() raises ValidationException for API >= 2026-01
- Clear error messages guide developers to correct method
- Prevents silent authentication failures
5. New Exception Type
- OAuthException for OAuth-specific errors
- Better error categorization and handling
Changes:
========
- Add Session.request_token_client_credentials() method (120 lines)
- Add Session.request_access_token() method with auto-detection (45 lines)
- Add Session._requires_client_credentials() version detection (20 lines)
- Add OAuthException class for OAuth errors
- Update request_token() with version check and helpful error
- Export OAuthException in shopify/__init__.py
- Add 12 comprehensive test cases
- Update CHANGELOG with detailed feature list
Implementation Details:
======================
- RFC 6749 Section 4.4 compliant
- 10-second timeout to prevent hanging
- Proper error handling for all failure scenarios
- Validates credentials before making requests
- Stores token and scopes in session automatically
- Returns full response with expiration time
- Version threshold: numeric_version >= 202601
Usage Examples:
===============
# Recommended: Automatic method
session = shopify.Session('store.myshopify.com', '2026-01')
shopify.Session.setup(api_key='client_id', secret='client_secret')
response = session.request_access_token() # Auto-detects OAuth flow
token = response['access_token']
# Explicit: Client credentials
response = session.request_token_client_credentials()
# Backward compatible: Old API versions
session = shopify.Session('store.myshopify.com', '2025-10')
token = session.request_access_token(callback_params)
Test Coverage:
==============
- OAuth success flow
- Missing credentials validation
- HTTP error handling
- Token reuse logic
- Version detection for 2026-01, 2026-04, 2025-10, 2024-10
- Old method blocking for new versions
- Automatic method selection for both flows
Statistics:
===========
- Lines added: 364
- Methods created: 3
- Tests added: 12
- Breaking changes: 0 (fully backward compatible)
Related:
========
https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/client-credentials-grant
https://datatracker.ietf.org/doc/html/rfc6749#section-4.4
- Add is_token_expired() method to check if token needs refresh with configurable buffer
- Add refresh_token_if_needed() for automatic proactive token refresh before expiration
- Add refresh_token() for manual forced token refresh (e.g., after permission changes)
- Add token_obtained_at and token_expires_at tracking fields to Session class
- request_token_client_credentials() now automatically stores expiration timestamps
- Add 9 comprehensive test cases covering all expiration and refresh scenarios
- Default 5-minute buffer before expiration to prevent authentication failures
- Only works with client credentials flow (API versions >= 2026-01)
- Backward compatible: gracefully handles authorization code flow without errors
This enhancement prevents authentication failures in long-running processes by
automatically refreshing tokens before they expire. Tokens from Shopify's client
credentials grant expire after 24 hours (86,399 seconds).
Example usage:
session = shopify.Session('store.myshopify.com', '2026-01')
session.request_access_token()
# Later, before API calls
result = session.refresh_token_if_needed()
if result:
print('Token was refreshed')
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add optional 'scope' parameter to all OAuth methods to enable requesting specific scopes instead of all configured scopes. This solves the issue where apps with multiple API types (Admin API + Customer Account API + Storefront API) cannot generate tokens through /admin/oauth/access_token because that endpoint only supports Admin API scopes. Changes: - Add scope parameter to request_token_client_credentials() - Add scope parameter to request_access_token() - Add scope parameter to refresh_token_if_needed() - Add scope parameter to refresh_token() - Implement scope normalization (convert commas to spaces for OAuth spec) - Add 7 comprehensive test cases for scope filtering functionality - Update CHANGELOG with feature documentation Use case: When a Shopify app has Customer Account API scopes configured (like customer_read_metaobjects), requesting a token without scope filtering fails because Shopify tries to grant ALL scopes through the Admin API endpoint. With scope filtering, developers can request only Admin API scopes: session.request_token_client_credentials(scope="read_products write_orders") Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
lvalics
commented
Jan 14, 2026
Author
lvalics
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SLA signed
Author
|
SLA signed |
Author
|
Need to add my other email. |
Author
|
Primary email address |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Complete OAuth 2.0 Client Credentials Grant Support for Shopify API 2026-01+
Overview
This PR adds comprehensive OAuth 2.0 Client Credentials Grant support required for Shopify API version 2026-01 and later, including automatic version detection, token expiration tracking, automatic refresh, and scope filtering for multi-API apps.
Background
Shopify API 2026-01+ Changes:
/admin/oauth/access_tokenendpoint only supports Admin API scopesPrevious Limitations:
Features
1. OAuth 2.0 Client Credentials Grant Support
New Methods:
Session.request_token_client_credentials()- Exchange client credentials for access tokenSession.request_access_token()- Smart method that automatically selects correct OAuth flow based on API versionNew Exception:
OAuthException- OAuth-specific errors with detailed error informationAutomatic Version Detection:
request_token()raisesValidationExceptionfor API versions >= 2026-01Example:
2. Token Expiration Tracking and Automatic Refresh
New Methods:
Session.is_token_expired(buffer_seconds=300)- Check if token is expired or expiring soonSession.refresh_token_if_needed(buffer_seconds=300)- Automatically refresh token if expired or expiring soonSession.refresh_token()- Manually force token refresh regardless of expiration statusToken Lifecycle Management:
token_obtained_atandtoken_expires_attimestampsExample:
3. OAuth Scope Filtering Support
Problem Solved:
When apps have multiple API types configured (Admin API + Customer Account API + Storefront API), requesting tokens through
/admin/oauth/access_tokenfails because that endpoint only supports Admin API scopes.Solution:
All OAuth methods now accept optional
scopeparameter to request specific scopes.New Functionality:
request_token_client_credentials(scope=None)request_access_token(scope=None)refresh_token_if_needed(scope=None)refresh_token(scope=None)Scope Normalization:
"read_products,write_products"→"read_products write_products"Example:
Use Case - Mixed API Types:
Shopify app configuration:
Before (fails):
After (works):
Complete Usage Example
Testing
Comprehensive Test Coverage:
Test Statistics:
Backward Compatibility
✓ No Breaking Changes
All new features are additive and backward compatible:
Migration Guide
For Existing Apps (API < 2026-01)
No changes required. Your code continues to work as before.
For New Apps (API >= 2026-01)
Option 1 - Simple (no scope filtering):
Option 2 - With automatic refresh:
Option 3 - With scope filtering (multi-API apps):
Implementation Details
RFC 6749 Compliance:
application/x-www-form-urlencoded)Security:
Error Handling:
OAuthExceptionfor OAuth-specific errors (401, 400, etc.)Checklist
token_obtained_at,token_expires_at)refresh_token_if_needed)refresh_token)OAuthExceptionfor OAuth errorsBenefits
This PR enables developers to:
✅ Build apps for Shopify API 2026-01+ using Client Credentials Grant
✅ Automatically handle token expiration and refresh
✅ Prevent authentication failures during long-running operations
✅ Configure multiple API types in a single Shopify app
✅ Use Customer Account API scopes alongside Admin API scopes
✅ Follow OAuth 2.0 best practices for scope filtering
✅ Seamlessly migrate from older API versions
Related: Implements OAuth 2.0 support for apps created in the new Shopify Dev Dashboard, which use Client Credentials Grant instead of Authorization Code Grant for server-to-server authentication.