Fix OAuth token exchange: use internal URL, add error logging
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m50s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m50s
The server-to-server token exchange was hitting the external URL (https://account.rose-ash.com/...) which can fail from inside Docker due to DNS/hairpin NAT. Now uses INTERNAL_URL_ACCOUNT (already set in both docker-compose files) for the POST. Adds logging at all three failure points so silent redirects are diagnosable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -64,6 +64,11 @@ class Settings:
|
||||
default_factory=lambda: os.environ.get("SECRET_KEY", "change-me-in-production")
|
||||
)
|
||||
|
||||
# Internal account URL for server-to-server token exchange (avoids external DNS/TLS)
|
||||
internal_account_url: str = field(
|
||||
default_factory=lambda: os.environ.get("INTERNAL_URL_ACCOUNT", "")
|
||||
)
|
||||
|
||||
# GPU/Streaming settings
|
||||
streaming_gpu_persist: bool = field(
|
||||
default_factory=lambda: os.environ.get("STREAMING_GPU_PERSIST", "0") == "1"
|
||||
|
||||
@@ -6,6 +6,7 @@ GET /auth/callback — exchange code for user info, set session cookie
|
||||
GET /auth/logout — clear cookie, redirect through account SSO logout
|
||||
"""
|
||||
|
||||
import logging
|
||||
import secrets
|
||||
import time
|
||||
|
||||
@@ -18,6 +19,7 @@ from artdag_common.middleware.auth import UserContext, set_auth_cookie, clear_au
|
||||
|
||||
from ..config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
|
||||
_signer = None
|
||||
@@ -119,24 +121,32 @@ async def callback(request: Request):
|
||||
return RedirectResponse(url="/", status_code=302)
|
||||
|
||||
# Exchange code for user info via account's token endpoint
|
||||
# Prefer internal URL (Docker overlay) to avoid external DNS/TLS issues
|
||||
token_url = settings.oauth_token_url
|
||||
if settings.internal_account_url:
|
||||
token_url = f"{settings.internal_account_url.rstrip('/')}/auth/oauth/token"
|
||||
|
||||
async with httpx.AsyncClient(timeout=10) as client:
|
||||
try:
|
||||
resp = await client.post(
|
||||
settings.oauth_token_url,
|
||||
token_url,
|
||||
json={
|
||||
"code": code,
|
||||
"client_id": settings.oauth_client_id,
|
||||
"redirect_uri": settings.oauth_redirect_uri,
|
||||
},
|
||||
)
|
||||
except httpx.HTTPError:
|
||||
except httpx.HTTPError as exc:
|
||||
logger.error("OAuth token exchange failed: %s %s", type(exc).__name__, exc)
|
||||
return RedirectResponse(url="/", status_code=302)
|
||||
|
||||
if resp.status_code != 200:
|
||||
logger.error("OAuth token exchange returned %s: %s", resp.status_code, resp.text[:200])
|
||||
return RedirectResponse(url="/", status_code=302)
|
||||
|
||||
data = resp.json()
|
||||
if "error" in data:
|
||||
logger.error("OAuth token exchange error: %s", data["error"])
|
||||
return RedirectResponse(url="/", status_code=302)
|
||||
|
||||
# Map OAuth response to artdag UserContext
|
||||
|
||||
@@ -41,6 +41,9 @@ class Settings:
|
||||
oauth_logout_url: str = os.environ.get("OAUTH_LOGOUT_URL", "https://account.rose-ash.com/auth/sso-logout/")
|
||||
secret_key: str = os.environ.get("SECRET_KEY", "change-me-in-production")
|
||||
|
||||
# Internal account URL for server-to-server token exchange (avoids external DNS/TLS)
|
||||
internal_account_url: str = os.environ.get("INTERNAL_URL_ACCOUNT", "")
|
||||
|
||||
def __post_init__(self):
|
||||
# Parse L1 servers
|
||||
l1_str = os.environ.get("L1_SERVERS", "https://celery-artdag.rose-ash.com")
|
||||
|
||||
@@ -6,6 +6,7 @@ GET /auth/callback — exchange code for user info, set session cookie
|
||||
GET /auth/logout — clear cookie, redirect through account SSO logout
|
||||
"""
|
||||
|
||||
import logging
|
||||
import secrets
|
||||
import time
|
||||
|
||||
@@ -18,6 +19,7 @@ from artdag_common.middleware.auth import UserContext, set_auth_cookie, clear_au
|
||||
|
||||
from ..config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
|
||||
_signer = None
|
||||
@@ -119,24 +121,32 @@ async def callback(request: Request):
|
||||
return RedirectResponse(url="/", status_code=302)
|
||||
|
||||
# Exchange code for user info via account's token endpoint
|
||||
# Prefer internal URL (Docker overlay) to avoid external DNS/TLS issues
|
||||
token_url = settings.oauth_token_url
|
||||
if settings.internal_account_url:
|
||||
token_url = f"{settings.internal_account_url.rstrip('/')}/auth/oauth/token"
|
||||
|
||||
async with httpx.AsyncClient(timeout=10) as client:
|
||||
try:
|
||||
resp = await client.post(
|
||||
settings.oauth_token_url,
|
||||
token_url,
|
||||
json={
|
||||
"code": code,
|
||||
"client_id": settings.oauth_client_id,
|
||||
"redirect_uri": settings.oauth_redirect_uri,
|
||||
},
|
||||
)
|
||||
except httpx.HTTPError:
|
||||
except httpx.HTTPError as exc:
|
||||
logger.error("OAuth token exchange failed: %s %s", type(exc).__name__, exc)
|
||||
return RedirectResponse(url="/", status_code=302)
|
||||
|
||||
if resp.status_code != 200:
|
||||
logger.error("OAuth token exchange returned %s: %s", resp.status_code, resp.text[:200])
|
||||
return RedirectResponse(url="/", status_code=302)
|
||||
|
||||
data = resp.json()
|
||||
if "error" in data:
|
||||
logger.error("OAuth token exchange error: %s", data["error"])
|
||||
return RedirectResponse(url="/", status_code=302)
|
||||
|
||||
# Map OAuth response to artdag UserContext
|
||||
|
||||
Reference in New Issue
Block a user