story writer backend migration complete, Blog writer SEO and story writer backend migration complete, Blog writer SEO and story writer frontend migration complete
This commit is contained in:
132
backend/services/integrations/wix/auth_utils.py
Normal file
132
backend/services/integrations/wix/auth_utils.py
Normal file
@@ -0,0 +1,132 @@
|
||||
"""
|
||||
Authentication utilities for Wix API requests.
|
||||
|
||||
Supports both OAuth Bearer tokens and API keys for Wix Headless apps.
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import Dict, Optional
|
||||
from loguru import logger
|
||||
|
||||
|
||||
def get_wix_headers(
|
||||
access_token: str,
|
||||
client_id: Optional[str] = None,
|
||||
extra: Optional[Dict[str, str]] = None
|
||||
) -> Dict[str, str]:
|
||||
"""
|
||||
Build headers for Wix API requests with automatic token type detection.
|
||||
|
||||
Supports:
|
||||
- OAuth Bearer tokens (JWT format: xxx.yyy.zzz)
|
||||
- Wix API keys (for Headless apps)
|
||||
|
||||
Args:
|
||||
access_token: OAuth token OR API key
|
||||
client_id: Optional Wix client ID
|
||||
extra: Additional headers to include
|
||||
|
||||
Returns:
|
||||
Headers dict with proper Authorization format
|
||||
"""
|
||||
headers: Dict[str, str] = {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
|
||||
if access_token:
|
||||
# Ensure access_token is a string (defensive check)
|
||||
if not isinstance(access_token, str):
|
||||
from services.integrations.wix.utils import normalize_token_string
|
||||
normalized = normalize_token_string(access_token)
|
||||
if normalized:
|
||||
access_token = normalized
|
||||
else:
|
||||
access_token = str(access_token)
|
||||
|
||||
token = access_token.strip()
|
||||
if token:
|
||||
# Detect token type
|
||||
# API keys are typically longer and don't have JWT structure (xxx.yyy.zzz)
|
||||
# JWT tokens have exactly 2 dots separating 3 parts
|
||||
# Wix OAuth tokens can have format "OauthNG.JWS.xxx.yyy.zzz"
|
||||
|
||||
# CRITICAL: Wix OAuth tokens can have format "OauthNG.JWS.xxx.yyy.zzz"
|
||||
# These should use "Bearer" prefix even though they have more than 2 dots
|
||||
if token.startswith('OauthNG.JWS.'):
|
||||
# Wix OAuth token - use Bearer prefix
|
||||
headers['Authorization'] = f'Bearer {token}'
|
||||
logger.debug(f"Using Wix OAuth token with Bearer prefix (OauthNG.JWS. format detected)")
|
||||
else:
|
||||
# Count dots - JWT has exactly 2 dots
|
||||
dot_count = token.count('.')
|
||||
|
||||
if dot_count == 2 and len(token) < 500:
|
||||
# Likely OAuth JWT token - use Bearer prefix
|
||||
headers['Authorization'] = f'Bearer {token}'
|
||||
logger.debug(f"Using OAuth Bearer token (JWT format detected)")
|
||||
else:
|
||||
# Likely API key - use directly without Bearer prefix
|
||||
headers['Authorization'] = token
|
||||
logger.debug(f"Using API key for authorization (non-JWT format detected)")
|
||||
|
||||
if client_id:
|
||||
headers['wix-client-id'] = client_id
|
||||
|
||||
if extra:
|
||||
headers.update(extra)
|
||||
|
||||
return headers
|
||||
|
||||
|
||||
def get_wix_api_key() -> Optional[str]:
|
||||
"""
|
||||
Get Wix API key from environment.
|
||||
|
||||
For Wix Headless apps, API keys provide admin-level access.
|
||||
|
||||
Returns:
|
||||
API key if set, None otherwise
|
||||
"""
|
||||
api_key = os.getenv('WIX_API_KEY')
|
||||
if api_key:
|
||||
logger.warning(f"✅ Wix API key found in environment ({len(api_key)} chars)")
|
||||
else:
|
||||
logger.warning("❌ No Wix API key in environment")
|
||||
return api_key
|
||||
|
||||
|
||||
def should_use_api_key(access_token: Optional[str] = None) -> bool:
|
||||
"""
|
||||
Determine if we should use API key instead of OAuth token.
|
||||
|
||||
Use API key if:
|
||||
- No OAuth token provided
|
||||
- OAuth token is getting 403 errors
|
||||
- API key is available in environment
|
||||
|
||||
Args:
|
||||
access_token: Optional OAuth token
|
||||
|
||||
Returns:
|
||||
True if should use API key, False otherwise
|
||||
"""
|
||||
# If no access token, check for API key
|
||||
if not access_token or not access_token.strip():
|
||||
return get_wix_api_key() is not None
|
||||
|
||||
# If access token looks like API key already, use it
|
||||
# Ensure access_token is a string (defensive check)
|
||||
if not isinstance(access_token, str):
|
||||
from services.integrations.wix.utils import normalize_token_string
|
||||
normalized = normalize_token_string(access_token)
|
||||
if normalized:
|
||||
access_token = normalized
|
||||
else:
|
||||
access_token = str(access_token)
|
||||
|
||||
token = access_token.strip()
|
||||
if token.count('.') != 2 or len(token) > 500:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
Reference in New Issue
Block a user